From e676f14c37646cc14c143f739f4d4afd56c35744 Mon Sep 17 00:00:00 2001 From: Sergey Ivanov Date: Sat, 7 Feb 2026 23:28:35 +0500 Subject: [PATCH 1/2] Add ignore-case text operations --- .../scripting/entity/AbstractText.java | 111 +++++++++++++++++- .../AbstractTextAndNumberOperationsTest.java | 7 ++ 2 files changed, 117 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/holyway/botplatform/scripting/entity/AbstractText.java b/src/main/java/ru/holyway/botplatform/scripting/entity/AbstractText.java index fad87bf..7a474ce 100644 --- a/src/main/java/ru/holyway/botplatform/scripting/entity/AbstractText.java +++ b/src/main/java/ru/holyway/botplatform/scripting/entity/AbstractText.java @@ -113,6 +113,19 @@ public Predicate startWith(String text) { }; } + public Predicate startWith(String text, boolean ignoreCase) { + return ctx -> { + String value = value().apply(ctx); + if (value == null) { + return false; + } + if (ignoreCase) { + return StringUtils.startsWithIgnoreCase(value, text); + } + return value.startsWith(text); + }; + } + public Predicate matches(String text) { return ctx -> { String value = value().apply(ctx); @@ -183,6 +196,16 @@ public AbstractText replace(String from, String to) { }); } + public AbstractText replace(String from, String to, boolean ignoreCase) { + return new Text(scriptContext -> { + String value = value().apply(scriptContext); + if (value == null) { + return null; + } + return replaceLiteral(value, from, to, ignoreCase); + }); + } + public AbstractText replaceAll(String from, String to) { return new Text(scriptContext -> { String value = value().apply(scriptContext); @@ -193,6 +216,16 @@ public AbstractText replaceAll(String from, String to) { }); } + public AbstractText replaceAll(String from, String to, boolean ignoreCase) { + return new Text(scriptContext -> { + String value = value().apply(scriptContext); + if (value == null) { + return null; + } + return replaceAllRegex(value, from, to, ignoreCase); + }); + } + public AbstractText path(final String path) { return new Text(scriptContext -> { String value = value().apply(scriptContext); @@ -224,6 +257,16 @@ public AbstractText replace(Function from, Function from, Function to, boolean ignoreCase) { + return new Text(scriptContext -> { + String value = value().apply(scriptContext); + if (value == null) { + return null; + } + return replaceLiteral(value, from.apply(scriptContext), to.apply(scriptContext), ignoreCase); + }); + } + public AbstractText replaceAll(Function from, Function to) { return new Text(scriptContext -> { String value = value().apply(scriptContext); @@ -234,6 +277,16 @@ public AbstractText replaceAll(Function from, Function from, Function to, boolean ignoreCase) { + return new Text(scriptContext -> { + String value = value().apply(scriptContext); + if (value == null) { + return null; + } + return replaceAllRegex(value, from.apply(scriptContext), to.apply(scriptContext), ignoreCase); + }); + } + public AbstractText replace(String from, Function to) { return new Text(scriptContext -> { String value = value().apply(scriptContext); @@ -244,6 +297,16 @@ public AbstractText replace(String from, Function to) { }); } + public AbstractText replace(String from, Function to, boolean ignoreCase) { + return new Text(scriptContext -> { + String value = value().apply(scriptContext); + if (value == null) { + return null; + } + return replaceLiteral(value, from, to.apply(scriptContext), ignoreCase); + }); + } + public AbstractText replaceAll(String from, Function to) { return new Text(scriptContext -> { String value = value().apply(scriptContext); @@ -254,6 +317,16 @@ public AbstractText replaceAll(String from, Function to) }); } + public AbstractText replaceAll(String from, Function to, boolean ignoreCase) { + return new Text(scriptContext -> { + String value = value().apply(scriptContext); + if (value == null) { + return null; + } + return replaceAllRegex(value, from, to.apply(scriptContext), ignoreCase); + }); + } + public AbstractText replace(Function from, String to) { return new Text(scriptContext -> { String value = value().apply(scriptContext); @@ -264,6 +337,16 @@ public AbstractText replace(Function from, String to) { }); } + public AbstractText replace(Function from, String to, boolean ignoreCase) { + return new Text(scriptContext -> { + String value = value().apply(scriptContext); + if (value == null) { + return null; + } + return replaceLiteral(value, from.apply(scriptContext), to, ignoreCase); + }); + } + public AbstractText replaceAll(Function from, String to) { return new Text(scriptContext -> { String value = value().apply(scriptContext); @@ -273,4 +356,30 @@ public AbstractText replaceAll(Function from, String to) return value.replaceAll(from.apply(scriptContext), to); }); } -} \ No newline at end of file + + public AbstractText replaceAll(Function from, String to, boolean ignoreCase) { + return new Text(scriptContext -> { + String value = value().apply(scriptContext); + if (value == null) { + return null; + } + return replaceAllRegex(value, from.apply(scriptContext), to, ignoreCase); + }); + } + + private static String replaceLiteral(String value, String from, String to, boolean ignoreCase) { + if (ignoreCase) { + return StringUtils.replaceIgnoreCase(value, from, to); + } + return value.replace(from, to); + } + + private static String replaceAllRegex(String value, String from, String to, boolean ignoreCase) { + if (!ignoreCase) { + return value.replaceAll(from, to); + } + Pattern pattern = Pattern.compile(from, Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE); + Matcher matcher = pattern.matcher(value); + return matcher.replaceAll(to); + } +} diff --git a/src/test/java/ru/holyway/botplatform/scripting/AbstractTextAndNumberOperationsTest.java b/src/test/java/ru/holyway/botplatform/scripting/AbstractTextAndNumberOperationsTest.java index bd03c8d..7e3dc7d 100644 --- a/src/test/java/ru/holyway/botplatform/scripting/AbstractTextAndNumberOperationsTest.java +++ b/src/test/java/ru/holyway/botplatform/scripting/AbstractTextAndNumberOperationsTest.java @@ -26,6 +26,8 @@ public void shouldEvaluateTextPredicatesAndTransforms() { assertTrue(text.contains("world").test(context)); assertTrue(text.cic("HELLO").test(context)); assertTrue(text.startWith(" ").test(context)); + assertTrue(text.startWith(" h", true).test(context)); + assertFalse(text.startWith(" h", false).test(context)); assertTrue(text.trim().eq("Hello world").test(context)); AbstractText regexGroup = text.regexp("(Hello) (world)", 2); @@ -39,6 +41,11 @@ public void shouldEvaluateTextPredicatesAndTransforms() { assertEquals("b", text.split("-", 1).apply(context)); assertNull(text.split("-", 5).apply(context)); + context.setContextValue("text", "Hello WORLD world"); + assertEquals("Hello there there", text.replace("world", "there", true).apply(context)); + assertEquals("Hello WORLD world", text.replace("world", "there", false).apply(context)); + assertEquals("Hello done done", text.replaceAll("w.rld", "done", true).apply(context)); + context.setContextValue("text", "json: {\"value\": 15}"); AbstractText path = new AbstractText.Text(ctx -> ctx.getContextValue("text").substring(6)).path("$.value"); assertEquals("15", path.apply(context)); From 0aef726f4717c5d77b22efbc360d2403c775053c Mon Sep 17 00:00:00 2001 From: Sergey Ivanov Date: Sat, 7 Feb 2026 23:33:55 +0500 Subject: [PATCH 2/2] Fix ignore-case replace implementation --- .../botplatform/scripting/entity/AbstractText.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/ru/holyway/botplatform/scripting/entity/AbstractText.java b/src/main/java/ru/holyway/botplatform/scripting/entity/AbstractText.java index 7a474ce..1c3e933 100644 --- a/src/main/java/ru/holyway/botplatform/scripting/entity/AbstractText.java +++ b/src/main/java/ru/holyway/botplatform/scripting/entity/AbstractText.java @@ -368,10 +368,12 @@ public AbstractText replaceAll(Function from, String to, } private static String replaceLiteral(String value, String from, String to, boolean ignoreCase) { - if (ignoreCase) { - return StringUtils.replaceIgnoreCase(value, from, to); + if (!ignoreCase) { + return value.replace(from, to); } - return value.replace(from, to); + Pattern pattern = Pattern.compile(Pattern.quote(from), Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE); + Matcher matcher = pattern.matcher(value); + return matcher.replaceAll(Matcher.quoteReplacement(to)); } private static String replaceAllRegex(String value, String from, String to, boolean ignoreCase) {