From 1fd62000b79a0a57a89b43919b667a9523fdd7fb Mon Sep 17 00:00:00 2001 From: Oswaldo Baptista Vicente Junior <45291656+oswaldobapvicjr@users.noreply.github.com> Date: Wed, 23 Oct 2024 23:46:11 -0300 Subject: [PATCH 1/2] New functions STR_SUBSTRING_AFTER/BEFORE --- .../config/ExpressionConfiguration.java | 4 ++ .../string/StringSubstringAfterFunction.java | 51 +++++++++++++++++++ .../string/StringSubstringBeforeFunction.java | 49 ++++++++++++++++++ .../functions/string/StringFunctionsTest.java | 31 +++++++++++ 4 files changed, 135 insertions(+) create mode 100644 src/main/java/com/ezylang/evalex/functions/string/StringSubstringAfterFunction.java create mode 100644 src/main/java/com/ezylang/evalex/functions/string/StringSubstringBeforeFunction.java diff --git a/src/main/java/com/ezylang/evalex/config/ExpressionConfiguration.java b/src/main/java/com/ezylang/evalex/config/ExpressionConfiguration.java index 057b5692..92eaf849 100644 --- a/src/main/java/com/ezylang/evalex/config/ExpressionConfiguration.java +++ b/src/main/java/com/ezylang/evalex/config/ExpressionConfiguration.java @@ -57,6 +57,8 @@ import com.ezylang.evalex.functions.string.StringMatchesFunction; import com.ezylang.evalex.functions.string.StringRightFunction; import com.ezylang.evalex.functions.string.StringStartsWithFunction; +import com.ezylang.evalex.functions.string.StringSubstringAfterFunction; +import com.ezylang.evalex.functions.string.StringSubstringBeforeFunction; import com.ezylang.evalex.functions.string.StringSubstringFunction; import com.ezylang.evalex.functions.string.StringTrimFunction; import com.ezylang.evalex.functions.string.StringUpperFunction; @@ -280,6 +282,8 @@ public class ExpressionConfiguration { Map.entry("STR_RIGHT", new StringRightFunction()), Map.entry("STR_STARTS_WITH", new StringStartsWithFunction()), Map.entry("STR_SUBSTRING", new StringSubstringFunction()), + Map.entry("STR_SUBSTRING_AFTER", new StringSubstringAfterFunction()), + Map.entry("STR_SUBSTRING_BEFORE", new StringSubstringBeforeFunction()), Map.entry("STR_TRIM", new StringTrimFunction()), Map.entry("STR_UPPER", new StringUpperFunction()), // date time functions diff --git a/src/main/java/com/ezylang/evalex/functions/string/StringSubstringAfterFunction.java b/src/main/java/com/ezylang/evalex/functions/string/StringSubstringAfterFunction.java new file mode 100644 index 00000000..9ec52d9b --- /dev/null +++ b/src/main/java/com/ezylang/evalex/functions/string/StringSubstringAfterFunction.java @@ -0,0 +1,51 @@ +/* + Copyright 2012-2024 Udo Klimaschewski + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package com.ezylang.evalex.functions.string; + +import com.ezylang.evalex.EvaluationException; +import com.ezylang.evalex.Expression; +import com.ezylang.evalex.data.EvaluationValue; +import com.ezylang.evalex.functions.AbstractFunction; +import com.ezylang.evalex.functions.FunctionParameter; +import com.ezylang.evalex.parser.Token; + +/** + * Returns the substring after the first occurrence of another (separator) string, or an empty + * string if the first string does not contain the second string. + * + *

For example: {@code STR_SUBSTRING_AFTER("2024/07/15", "/")} returns {@code "07/15"}. + * + * @author oswaldobapvicjr + */ +@FunctionParameter(name = "string") +@FunctionParameter(name = "separator") +public class StringSubstringAfterFunction extends AbstractFunction { + private static final String STR_EMPTY = ""; + + @Override + public EvaluationValue evaluate( + Expression expression, Token functionToken, EvaluationValue... parameterValues) + throws EvaluationException { + String string = parameterValues[0].getStringValue(); + String separator = parameterValues[1].getStringValue(); + return expression.convertValue(substringAfter(string, separator)); + } + + private String substringAfter(String string, String separator) { + int position = string.indexOf(separator); + return (position == -1) ? STR_EMPTY : string.substring(position + separator.length()); + } +} diff --git a/src/main/java/com/ezylang/evalex/functions/string/StringSubstringBeforeFunction.java b/src/main/java/com/ezylang/evalex/functions/string/StringSubstringBeforeFunction.java new file mode 100644 index 00000000..f3cebfbf --- /dev/null +++ b/src/main/java/com/ezylang/evalex/functions/string/StringSubstringBeforeFunction.java @@ -0,0 +1,49 @@ +/* + Copyright 2012-2024 Udo Klimaschewski + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package com.ezylang.evalex.functions.string; + +import com.ezylang.evalex.EvaluationException; +import com.ezylang.evalex.Expression; +import com.ezylang.evalex.data.EvaluationValue; +import com.ezylang.evalex.functions.AbstractFunction; +import com.ezylang.evalex.functions.FunctionParameter; +import com.ezylang.evalex.parser.Token; + +/** + * Returns the substring before the first occurrence of another (separator) string, or the original + * string if it does not contain the second string. + * + *

For example: {@code STR_SUBSTRING_BEFORE("2024/07/15", "/")} returns {@code "2024"}. + * + * @author oswaldobapvicjr + */ +@FunctionParameter(name = "string") +@FunctionParameter(name = "separator") +public class StringSubstringBeforeFunction extends AbstractFunction { + @Override + public EvaluationValue evaluate( + Expression expression, Token functionToken, EvaluationValue... parameterValues) + throws EvaluationException { + String string = parameterValues[0].getStringValue(); + String separator = parameterValues[1].getStringValue(); + return expression.convertValue(substringBefore(string, separator)); + } + + private String substringBefore(String string, String separator) { + int position = string.indexOf(separator); + return (position == -1) ? string : string.substring(0, position); + } +} diff --git a/src/test/java/com/ezylang/evalex/functions/string/StringFunctionsTest.java b/src/test/java/com/ezylang/evalex/functions/string/StringFunctionsTest.java index 974f607a..936c2cd4 100644 --- a/src/test/java/com/ezylang/evalex/functions/string/StringFunctionsTest.java +++ b/src/test/java/com/ezylang/evalex/functions/string/StringFunctionsTest.java @@ -202,6 +202,37 @@ void testMatches(String expression, String expectedResult) assertExpressionHasExpectedResult(expression, expectedResult); } + @ParameterizedTest + @CsvSource( + delimiter = ':', + value = { + "STR_SUBSTRING_AFTER(\"myFile.json\", \".\") : json", + "STR_SUBSTRING_AFTER(\"2024/07/15\", \"/\") : 07/15", + "STR_SUBSTRING_AFTER(\"2024/07/15\", \"20\") : 24/07/15", + "STR_SUBSTRING_AFTER(\"test\", \"\") : 'test'", + "STR_SUBSTRING_AFTER(\"test\", \"a\") : ''", + "STR_SUBSTRING_AFTER(\"\", \"\") : ''" + }) + void testSubstringAfter(String expression, String expectedResult) + throws EvaluationException, ParseException { + assertExpressionHasExpectedResult(expression, expectedResult); + } + + @ParameterizedTest + @CsvSource( + delimiter = ':', + value = { + "STR_SUBSTRING_BEFORE(\"myFile.json\", \".\") : myFile", + "STR_SUBSTRING_BEFORE(\"2024/07/15\", \"/\") : 2024", + "STR_SUBSTRING_BEFORE(\"test\", \"\") : ''", + "STR_SUBSTRING_BEFORE(\"test\", \"a\") : 'test'", + "STR_SUBSTRING_BEFORE(\"\", \"\") : ''" + }) + void testSubstringBefore(String expression, String expectedResult) + throws EvaluationException, ParseException { + assertExpressionHasExpectedResult(expression, expectedResult); + } + @ParameterizedTest @CsvSource( delimiter = ':', From e2977d18ae776af58a1be579eaf83f3e822bf519 Mon Sep 17 00:00:00 2001 From: Oswaldo Baptista Vicente Junior <45291656+oswaldobapvicjr@users.noreply.github.com> Date: Wed, 23 Oct 2024 23:57:00 -0300 Subject: [PATCH 2/2] Update functions.md --- docs/references/functions.md | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/docs/references/functions.md b/docs/references/functions.md index 013eb25e..cc270a8a 100644 --- a/docs/references/functions.md +++ b/docs/references/functions.md @@ -33,20 +33,22 @@ Available through the _ExpressionConfiguration.StandardFunctionsDictionary_ cons ### String Functions -| Name | Description | -|-------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------| -| STR_CONTAINS(string, substring) | Returns true if the string contains the substring (case-insensitive) | -| STR_ENDS_WITH(string, substring) | Returns true if the string ends with the substring (case-sensitive) | -| STR_FORMAT(format [,argument, ...]) | Returns a formatted string using the specified format string and arguments, using the configured locale | -| STR_LEFT(value, n) | Returns the first n characters from the left of the given string | -| STR_LENGTH(string) | Returns the length of the string | -| STR_LOWER(value) | Converts the given value to lower case | -| STR_MATCHES(string, pattern) | Returns true if the string matches the RegEx pattern | -| STR_RIGHT(value, n) | Returns the last n characters from the left of the given string | -| STR_STARTS_WITH(string, substring) | Returns true if the string starts with the substring (case-sensitive) | -| STR_SUBSTRING(string, start[, end]) | Returns a substring of the given string, starting at the _start_ index and ending at the _end_ index (the end of the string if not specified) | -| STR_TRIM(string) | Returns the given string with all leading and trailing space removed. | -| STR_UPPER(value) | Converts the given value to upper case | +| Name | Description | +|-----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------| +| STR_CONTAINS(string, substring) | Returns true if the string contains the substring (case-insensitive) | +| STR_ENDS_WITH(string, substring) | Returns true if the string ends with the substring (case-sensitive) | +| STR_FORMAT(format [,argument, ...]) | Returns a formatted string using the specified format string and arguments, using the configured locale | +| STR_LEFT(value, n) | Returns the first n characters from the left of the given string | +| STR_LENGTH(string) | Returns the length of the string | +| STR_LOWER(value) | Converts the given value to lower case | +| STR_MATCHES(string, pattern) | Returns true if the string matches the RegEx pattern | +| STR_RIGHT(value, n) | Returns the last n characters from the left of the given string | +| STR_STARTS_WITH(string, substring) | Returns true if the string starts with the substring (case-sensitive) | +| STR_SUBSTRING(string, start[, end]) | Returns a substring of the given string, starting at the _start_ index and ending at the _end_ index (the end of the string if not specified) | +| STR_SUBSTRING_AFTER(string, separator) | Returns the substring after the first occurrence of the _separator_ string on the given _string_ | +| STR_SUBSTRING_BEFORE(string, separator) | Returns the substring before the first occurrence of the _separator_ string on the given _string_ | +| STR_TRIM(string) | Returns the given string with all leading and trailing space removed. | +| STR_UPPER(value) | Converts the given value to upper case | ### Trigonometric Functions