This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 2972b41e58f9 CAMEL-22894: extract math and string Simple functions 
into dedicated factories (#23388)
2972b41e58f9 is described below

commit 2972b41e58f949dfae8e2a9f87bf0c8c6f7c42d8
Author: Adriano Machado <[email protected]>
AuthorDate: Thu May 21 02:01:07 2026 -0400

    CAMEL-22894: extract math and string Simple functions into dedicated 
factories (#23388)
    
    Extract abs/floor/ceil/sum/max/min/average into MathFunctionFactory and
    replace/substring/substringBefore/substringAfter/substringBetween/contains/
    trim/val/capitalize/pad/concat/quote/safeQuote/unquote/uppercase/lowercase/
    length/size/normalizeWhitespace into StringFunctionFactory.
    
    Consolidates the full codeSplitSafe implementation into SimpleFunctionHelper
    (deprecating the delegation stub on SimpleFunctionExpression). Reduces
    SimpleFunctionExpression from ~3600 to ~2300 lines.
    
    Also fix a few typos present on the Simple language documentation.
    
    Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
    
    rh-pre-commit.version: 2.3.2
    rh-pre-commit.check-secrets: ENABLED
---
 .../modules/languages/pages/simple-language.adoc   |   18 +-
 .../language/simple/SimpleFunctionDispatcher.java  |    6 +-
 .../language/simple/SimpleFunctionHelper.java      |  111 +-
 .../simple/ast/SimpleFunctionExpression.java       | 1405 +-------------------
 .../simple/functions/MathFunctionFactory.java      |  164 +++
 .../simple/functions/StringFunctionFactory.java    |  687 ++++++++++
 .../simple/functions/MathFunctionFactoryTest.java  |  123 ++
 .../functions/StringFunctionFactoryTest.java       |  319 +++++
 8 files changed, 1425 insertions(+), 1408 deletions(-)

diff --git 
a/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
 
b/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
index cd1a6a4dff83..5e9feaee135b 100644
--- 
a/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
+++ 
b/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
@@ -362,13 +362,13 @@ The condition functions is small functions that mostly 
evaluates to a `boolean`
 |====
 |Function |Response Type |Description
 |`assert(exp,msg)` | `null` | Evaluates the expression and throws an exception 
with the message if the condition is false. This function is not supported when 
using csimple.
-|`contains(text`) | `boolean` | Returns true if the message body contains part 
of the text (ignore case)
-|`contains(exp,text`) | `boolean` | Returns true if the expression contains 
part of the text (ignore case)
-|`iif(predicate,trueExp,falseExp`) | `Object` | The inlined if function 
evaluates the predicate expression and returns the value of _trueExp_ if the 
predicate is `true`, otherwise the value of `falseExp` is returned. This 
function is similar to the ternary operator in Java.
+|`contains(text)` | `boolean` | Returns true if the message body contains part 
of the text (ignore case)
+|`contains(exp,text)` | `boolean` | Returns true if the expression contains 
part of the text (ignore case)
+|`iif(predicate,trueExp,falseExp)` | `Object` | The inlined if function 
evaluates the predicate expression and returns the value of _trueExp_ if the 
predicate is `true`, otherwise the value of `falseExp` is returned. This 
function is similar to the ternary operator in Java.
 |`isEmpty` | `boolean` | Whether the message body is `null` or empty (list/map 
types are tested if they have 0 elements).
 |`isEmpty(exp)` | `boolean` | Whether the expression is `null` or empty 
(list/map types are tested if they have 0 elements).
-|`isAlpha()` | `boolean` | Whether the message body is numeric value (A..Z). 
For more advanced checks use the `regex` operator.
-|`isAlpha(exp)` | `boolean` | Whether the expression is numeric value (A..Z). 
For more advanced checks use the `regex` operator.
+|`isAlpha()` | `boolean` | Whether the message body is alphabetic value 
(A..Z). For more advanced checks use the `regex` operator.
+|`isAlpha(exp)` | `boolean` | Whether the expression is alphabetic value 
(A..Z). For more advanced checks use the `regex` operator.
 |`isAlphaNumeric()` | `boolean` | Whether the message body is alphanumeric 
value (A..Z0-9). For more advanced checks use the `regex` operator.
 |`isAlphaNumeric(exp)` | `boolean` | Whether the expression is alphanumeric 
value (A..Z0-9). For more advanced checks use the `regex` operator.
 |`isNumeric()` | `boolean` | Whether the message body is numeric value (0..9). 
For more advanced checks use the `regex` operator.
@@ -537,14 +537,14 @@ The string functions is various functions to work with 
values that are String an
 |`safeQuote()` | `String` | Returns the message body safely quoted if needed
 |`safeQuote(exp)` | `String` | Returns the expression safely quoted if needed
 |`substring(num1)` | `String` | Returns a substring of the message body. If 
the number is positive, then the returned string is clipped from the beginning. 
If the number is negative, then the returned string is clipped from the ending.
-|`substring(num1,num2)` | `String` | Returns a substring of the message body. 
If the number is positive, then the returned string is clipped from the 
beginning. If the number is negative, then the returned string is clipped from 
the ending.
-|`substring(num1,num2,exp)` | `String` | Returns a substring of the given 
expression. If the number is positive, then the returned string is clipped from 
the beginning. If the number is negative, then the returned string is clipped 
from the ending.
+|`substring(num1,num2)` | `String` | Returns a substring of the message body. 
`num1` clips from the beginning, `num2` clips from the ending. Negative values 
clip from the opposite end.
+|`substring(num1,num2,exp)` | `String` | Returns a substring of the given 
expression. `num1` clips from the beginning, `num2` clips from the ending. 
Negative values clip from the opposite end.
 |`substringAfter(after)` | `String` | Returns a substring of the message body 
that comes after. Returns `null` if nothing comes after.
 |`substringAfter(exp,after)` | `String` | Returns a substring of the 
expression that comes after. Returns `null` if nothing comes after.
 |`substringBefore(before)` | `String` | Returns a substring of the message 
body that comes before. Returns `null` if nothing comes before.
 |`substringBefore(exp,before)` | `String` | Returns a substring of the 
expression that comes before. Returns `null` if nothing comes before.
-|`substringBetween(after,before` | `String` | Returns a substring of the 
message body that are between before and after. Returns `null` if nothing comes 
between.
-|`substringBetween(exp,after,before` | `String` | Returns a substring of the 
expression that are between before and after. Returns `null` if nothing comes 
between.
+|`substringBetween(after,before)` | `String` | Returns a substring of the 
message body that are between before and after. Returns `null` if nothing comes 
between.
+|`substringBetween(exp,after,before)` | `String` | Returns a substring of the 
expression that are between before and after. Returns `null` if nothing comes 
between.
 |`trim()` | `String` | The trim function trims the message body by removing 
all leading and trailing white spaces.
 |`trim(exp)` | `String` | The trim function trims the expression by removing 
all leading and trailing white spaces.
 |`unquote()` | `String` | Returns the message body with any leading/ending 
quotes removed
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionDispatcher.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionDispatcher.java
index 0f41262c81dc..cca342857ee1 100644
--- 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionDispatcher.java
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionDispatcher.java
@@ -25,8 +25,10 @@ import 
org.apache.camel.language.simple.functions.BodyFunctionFactory;
 import org.apache.camel.language.simple.functions.CollateFunctionFactory;
 import org.apache.camel.language.simple.functions.HeaderFunctionFactory;
 import org.apache.camel.language.simple.functions.JoinFunctionFactory;
+import org.apache.camel.language.simple.functions.MathFunctionFactory;
 import org.apache.camel.language.simple.functions.RandomFunctionFactory;
 import org.apache.camel.language.simple.functions.SkipFunctionFactory;
+import org.apache.camel.language.simple.functions.StringFunctionFactory;
 import org.apache.camel.language.simple.functions.VariableFunctionFactory;
 import org.apache.camel.spi.SimpleLanguageFunctionFactory;
 import org.apache.camel.support.ResolverHelper;
@@ -57,7 +59,9 @@ public final class SimpleFunctionDispatcher {
             new RandomFunctionFactory(),
             new SkipFunctionFactory(),
             new CollateFunctionFactory(),
-            new JoinFunctionFactory());
+            new JoinFunctionFactory(),
+            new MathFunctionFactory(),
+            new StringFunctionFactory());
 
     private static final List<Entry> EXPRESSION_ENTRIES = List.of(
             new Entry("camel-attachments", 
SimpleFunctionDispatcher::isAttachmentFunction),
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionHelper.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionHelper.java
index 6e11f57f7c7a..ce70af1b4010 100644
--- 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionHelper.java
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionHelper.java
@@ -179,6 +179,7 @@ public final class SimpleFunctionHelper {
                     input = input.trim();
                 }
             }
+            // no separator in data, so return single string with input as is
             return new String[] { input };
         }
 
@@ -196,6 +197,7 @@ public final class SimpleFunctionHelper {
             boolean isQuoting = singleQuoted || doubleQuoted;
             boolean last = i == input.length() - 1;
 
+            // do not split inside code blocks
             if (input.indexOf(BaseSimpleParser.CODE_START, i) == i) {
                 codeLevel++;
                 sb.append(BaseSimpleParser.CODE_START);
@@ -213,65 +215,92 @@ public final class SimpleFunctionHelper {
             }
 
             if (!doubleQuoted && ch == '\'') {
-                if (!singleQuoted) {
-                    singleQuoted = true;
+                if (singleQuoted && prev == ch && sb.isEmpty()) {
+                    // its an empty quote so add empty text
                     if (keepQuotes) {
-                        sb.append(ch);
+                        answer.add("''");
+                    } else {
+                        answer.add("");
                     }
-                    continue;
-                } else if (prev != '\\') {
-                    singleQuoted = false;
-                    if (keepQuotes) {
-                        sb.append(ch);
+                }
+                // special logic needed if this quote is the end
+                if (last) {
+                    if (singleQuoted && !sb.isEmpty()) {
+                        String text = sb.toString();
+                        // do not trim a quoted string
+                        if (keepQuotes) {
+                            answer.add(text + "'"); // append ending quote
+                        } else {
+                            answer.add(text);
+                        }
+                        sb.setLength(0);
                     }
-                    continue;
+                    break; // break out as we are finished
+                }
+                singleQuoted = !singleQuoted;
+                if (keepQuotes) {
+                    sb.append(ch);
                 }
+                continue;
             } else if (!singleQuoted && ch == '"') {
-                if (!doubleQuoted) {
-                    doubleQuoted = true;
+                if (doubleQuoted && prev == ch && sb.isEmpty()) {
+                    // its an empty quote so add empty text
                     if (keepQuotes) {
-                        sb.append(ch);
+                        answer.add("\""); // append ending quote
+                    } else {
+                        answer.add("");
                     }
-                    continue;
-                } else if (prev != '\\') {
-                    doubleQuoted = false;
-                    if (keepQuotes) {
-                        sb.append(ch);
+                }
+                // special logic needed if this quote is the end
+                if (last) {
+                    if (doubleQuoted && !sb.isEmpty()) {
+                        String text = sb.toString();
+                        // do not trim a quoted string
+                        if (keepQuotes) {
+                            answer.add(text + "\"");
+                        } else {
+                            answer.add(text);
+                        }
+                        sb.setLength(0);
                     }
-                    continue;
+                    break; // break out as we are finished
                 }
-            }
-
-            if (isQuoting) {
-                sb.append(ch);
+                doubleQuoted = !doubleQuoted;
+                if (keepQuotes) {
+                    sb.append(ch);
+                }
+                continue;
+            } else if (!isQuoting && ch == separator) {
+                separating = true;
+                // add as answer if we are not in a quote
+                if (!sb.isEmpty()) {
+                    String text = sb.toString();
+                    if (trim) {
+                        text = text.trim();
+                    }
+                    answer.add(text);
+                    sb.setLength(0);
+                }
+                // we should avoid adding the separator
                 continue;
             }
 
-            if (ch == separator) {
-                if (separating) {
-                    continue;
-                }
-                String s = sb.toString();
-                if (trim) {
-                    s = s.trim();
-                }
-                answer.add(s);
-                sb.setLength(0);
-                separating = true;
+            if (trim && !isQuoting && separating && separator != ' ' && ch == 
' ') {
                 continue;
-            } else if (separating) {
-                separating = false;
             }
+            separating = false;
 
+            // append char
             sb.append(ch);
+        }
 
-            if (last) {
-                String s = sb.toString();
-                if (trim) {
-                    s = s.trim();
-                }
-                answer.add(s);
+        // any leftover
+        if (!sb.isEmpty()) {
+            String text = sb.toString();
+            if (trim) {
+                text = text.trim();
             }
+            answer.add(text);
         }
 
         return answer.toArray(new String[0]);
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
index 2e5d7ba037b3..f0b291e5aaff 100644
--- 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
@@ -17,9 +17,7 @@
 package org.apache.camel.language.simple.ast;
 
 import java.net.URISyntaxException;
-import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.List;
 import java.util.Map;
 import java.util.StringJoiner;
 import java.util.stream.Collectors;
@@ -389,11 +387,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
         if (misc != null) {
             return misc;
         }
-        // math functions
-        Expression math = createSimpleExpressionMath(function);
-        if (math != null) {
-            return math;
-        }
 
         // functions from external components (attachments, base64, html, ...)
         Expression external = 
SimpleFunctionDispatcher.tryCreateExternal(camelContext, function, 
token.getIndex());
@@ -707,169 +700,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             return SimpleExpressionBuilder.setVariableExpression(name, type, 
exp);
         }
 
-        // replace function
-        remainder = ifStartsWithReturnRemainder("replace(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (values == null || ObjectHelper.isEmpty(values)) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${replace(from,to)} or 
${replace(from,to,expression)} was: " + function,
-                        token.getIndex());
-            }
-            String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',', 
false);
-            if (tokens.length > 3) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${replace(from,to,expression)} was: " + 
function, token.getIndex());
-            }
-            String from = StringHelper.xmlDecode(tokens[0]);
-            String to = StringHelper.xmlDecode(tokens[1]);
-            // special to make it easy to replace to an empty value (ie remove)
-            if ("&empty;".equals(to)) {
-                to = "";
-            }
-            String exp = "${body}";
-            if (tokens.length == 3) {
-                exp = tokens[2];
-            }
-            return SimpleExpressionBuilder.replaceExpression(exp, from, to);
-        }
-
-        // substring function
-        remainder = ifStartsWithReturnRemainder("substring(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (values == null || ObjectHelper.isEmpty(values)) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${substring(num)}, 
${substring(num,num)}, or ${substring(num,num,expression)} was: "
-                                                + function,
-                        token.getIndex());
-            }
-            String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',', 
false);
-            if (tokens.length > 3) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${substring(num,num,expression)} was: " 
+ function, token.getIndex());
-            }
-            String num1 = tokens[0];
-            String num2 = "0";
-            if (tokens.length > 1) {
-                num2 = tokens[1];
-            }
-            String exp = "${body}";
-            if (tokens.length == 3) {
-                exp = tokens[2];
-            }
-            return SimpleExpressionBuilder.substringExpression(exp, num1, 
num2);
-        }
-        remainder = ifStartsWithReturnRemainder("substringBefore(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (values == null || ObjectHelper.isEmpty(values)) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${substringBefore(exp)} or 
${substringBefore(exp,exp)} was: "
-                                                + function,
-                        token.getIndex());
-            }
-            String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',', 
false);
-            if (tokens.length > 2) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${substringBefore(exp)} or 
${substringBefore(exp,exp)} was: "
-                                                + function,
-                        token.getIndex());
-            }
-            String exp1 = "${body}";
-            String before;
-            if (tokens.length == 2) {
-                exp1 = tokens[0];
-                before = tokens[1];
-            } else {
-                before = tokens[0];
-            }
-            return SimpleExpressionBuilder.substringBeforeExpression(exp1, 
before);
-        }
-        remainder = ifStartsWithReturnRemainder("substringAfter(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (values == null || ObjectHelper.isEmpty(values)) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${substringAfter(exp)} or 
${substringAfter(exp,exp)} was: "
-                                                + function,
-                        token.getIndex());
-            }
-            String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',', 
false);
-            if (tokens.length > 2) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${substringAfter(exp)} or 
${substringAfter(exp,exp)} was: "
-                                                + function,
-                        token.getIndex());
-            }
-            String exp1 = "${body}";
-            String after;
-            if (tokens.length == 2) {
-                exp1 = tokens[0];
-                after = tokens[1];
-            } else {
-                after = tokens[0];
-            }
-            return SimpleExpressionBuilder.substringAfterExpression(exp1, 
after);
-        }
-        remainder = ifStartsWithReturnRemainder("substringBetween(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (values == null || ObjectHelper.isEmpty(values)) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${substringBetween(after,before)} or 
${substringAfter(exp,after,before)} was: "
-                                                + function,
-                        token.getIndex());
-            }
-            String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',', 
false);
-            if (tokens.length < 2 || tokens.length > 3) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${substringBetween(after,before)} or 
${substringAfter(exp,after,before)} was: "
-                                                + function,
-                        token.getIndex());
-            }
-            String exp1 = "${body}";
-            String after;
-            String before;
-            if (tokens.length == 3) {
-                exp1 = tokens[0];
-                after = tokens[1];
-                before = tokens[2];
-            } else {
-                after = tokens[0];
-                before = tokens[1];
-            }
-            return SimpleExpressionBuilder.substringBetweenExpression(exp1, 
after, before);
-        }
-
-        // contains function
-        remainder = ifStartsWithReturnRemainder("contains(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (values == null || ObjectHelper.isEmpty(values)) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${contains(text)} or 
${contains(exp,text)} was: "
-                                                + function,
-                        token.getIndex());
-            }
-            String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',', 
false);
-            if (tokens.length < 1 || tokens.length > 2) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${contains(text)} or 
${contains(exp,text)} was: "
-                                                + function,
-                        token.getIndex());
-            }
-            String exp = "${body}";
-            String pattern;
-            if (tokens.length == 1) {
-                pattern = tokens[0];
-            } else {
-                exp = tokens[0];
-                pattern = tokens[1];
-            }
-            return SimpleExpressionBuilder.containsExpression(exp, pattern);
-        }
-
         // range function
         remainder = ifStartsWithReturnRemainder("range(", function);
         if (remainder != null) {
@@ -1157,129 +987,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             return SimpleExpressionBuilder.kindOfTypeExpression(exp);
         }
 
-        // quote function
-        remainder = ifStartsWithReturnRemainder("quote(", function);
-        if (remainder != null) {
-            String exp = null;
-            String value = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(value)) {
-                exp = StringHelper.removeQuotes(value);
-            }
-            return SimpleExpressionBuilder.quoteExpression(exp);
-        }
-        // safeQuote function
-        remainder = ifStartsWithReturnRemainder("safeQuote(", function);
-        if (remainder != null) {
-            String exp = null;
-            String value = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(value)) {
-                exp = StringHelper.removeQuotes(value);
-            }
-            return SimpleExpressionBuilder.safeQuoteExpression(exp);
-        }
-        // unquote function
-        remainder = ifStartsWithReturnRemainder("unquote(", function);
-        if (remainder != null) {
-            String exp = null;
-            String value = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(value)) {
-                exp = StringHelper.removeQuotes(value);
-            }
-            return SimpleExpressionBuilder.unquoteExpression(exp);
-        }
-
-        // trim function
-        remainder = ifStartsWithReturnRemainder("trim(", function);
-        if (remainder != null) {
-            String exp = null;
-            String value = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(value)) {
-                exp = StringHelper.removeQuotes(value);
-            }
-            return SimpleExpressionBuilder.trimExpression(exp);
-        }
-
-        // val function
-        remainder = ifStartsWithReturnRemainder("val(", function);
-        if (remainder != null) {
-            String exp = null;
-            String value = StringHelper.beforeLast(remainder, ")");
-            if (value == null || ObjectHelper.isEmpty(value)) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${val(exp)} was: " + function,
-                        token.getIndex());
-            }
-            return ExpressionBuilder.simpleExpression(value);
-        }
-
-        // capitalize
-        remainder = ifStartsWithReturnRemainder("capitalize(", function);
-        if (remainder != null) {
-            String exp = null;
-            String value = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(value)) {
-                exp = StringHelper.removeQuotes(value);
-            }
-            return SimpleExpressionBuilder.capitalizeExpression(exp);
-        }
-
-        // pad function
-        remainder = ifStartsWithReturnRemainder("pad(", function);
-        if (remainder != null) {
-            String exp;
-            String len;
-            String separator = null;
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (values == null || ObjectHelper.isEmpty(values)) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${pad(len)} or ${pad(exp,len)} or 
${pad(exp,len,separator)} was: " + function,
-                        token.getIndex());
-            }
-            String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',', 
true, true);
-            if (tokens.length < 2 || tokens.length > 3) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${pad(exp,len)} or 
${pad(exp,len,separator)} was: " + function,
-                        token.getIndex());
-            }
-            exp = StringHelper.removeQuotes(tokens[0]);
-            len = StringHelper.removeQuotes(tokens[1]);
-            if (tokens.length == 3) {
-                separator = StringHelper.removeQuotes(tokens[2]);
-            }
-            return SimpleExpressionBuilder.padExpression(exp, len, separator);
-        }
-
-        // concat function
-        remainder = ifStartsWithReturnRemainder("concat(", function);
-        if (remainder != null) {
-            String separator = null;
-            String exp1 = "${body}";
-            String exp2;
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (values == null || ObjectHelper.isEmpty(values)) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${concat(exp)} or ${concat(exp,exp)} or 
${concat(exp,exp,separator)} was: " + function,
-                        token.getIndex());
-            }
-            if (values.contains(",")) {
-                String[] tokens = StringQuoteHelper.splitSafeQuote(values, 
',', true, true);
-                if (tokens.length > 3) {
-                    throw new SimpleParserException(
-                            "Valid syntax: ${concat(exp)} or 
${concat(exp,exp)} or ${concat(exp,exp,separator)} was: "
-                                                    + function,
-                            token.getIndex());
-                }
-                exp1 = StringHelper.removeQuotes(tokens[0]);
-                exp2 = StringHelper.removeQuotes(tokens[1]);
-                if (tokens.length == 3) {
-                    separator = StringHelper.removeQuotes(tokens[2]);
-                }
-            } else {
-                exp2 = StringHelper.removeQuotes(values.trim());
-            }
-            return SimpleExpressionBuilder.concatExpression(exp1, exp2, 
separator);
-        }
-
         // throwException function
         remainder = ifStartsWithReturnRemainder("throwException(", function);
         if (remainder != null) {
@@ -1365,58 +1072,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             }
         }
 
-        // uppercase function
-        remainder = ifStartsWithReturnRemainder("uppercase(", function);
-        if (remainder != null) {
-            String exp = null;
-            String value = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(value)) {
-                exp = StringHelper.removeQuotes(value);
-            }
-            return SimpleExpressionBuilder.uppercaseExpression(exp);
-        }
-        // lowercase function
-        remainder = ifStartsWithReturnRemainder("lowercase(", function);
-        if (remainder != null) {
-            String exp = null;
-            String value = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(value)) {
-                exp = StringHelper.removeQuotes(value);
-            }
-            return SimpleExpressionBuilder.lowercaseExpression(exp);
-        }
-
-        // length function
-        remainder = ifStartsWithReturnRemainder("length(", function);
-        if (remainder != null) {
-            String exp = null;
-            String value = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(value)) {
-                exp = StringHelper.removeQuotes(value);
-            }
-            return SimpleExpressionBuilder.lengthExpression(exp);
-        }
-        // size function
-        remainder = ifStartsWithReturnRemainder("size(", function);
-        if (remainder != null) {
-            String exp = null;
-            String value = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(value)) {
-                exp = StringHelper.removeQuotes(value);
-            }
-            return SimpleExpressionBuilder.sizeExpression(exp);
-        }
-        // normalizeWhitespace function
-        remainder = ifStartsWithReturnRemainder("normalizeWhitespace(", 
function);
-        if (remainder != null) {
-            String exp = null;
-            String value = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(value)) {
-                exp = StringHelper.removeQuotes(value);
-            }
-            return SimpleExpressionBuilder.normalizeWhitespaceExpression(exp);
-        }
-
         // messageHistory function
         remainder = ifStartsWithReturnRemainder("messageHistory", function);
         if (remainder != null) {
@@ -1539,109 +1194,32 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
         return null;
     }
 
-    private Expression createSimpleExpressionMath(String function) {
-        String remainder;
+    @Deprecated(since = "4.21")
+    public static String ifStartsWithReturnRemainder(String prefix, String 
text) {
+        return SimpleFunctionHelper.ifStartsWithReturnRemainder(prefix, text);
+    }
 
-        // abs function
-        remainder = ifStartsWithReturnRemainder("abs(", function);
-        if (remainder != null) {
-            String exp = null;
-            String value = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(value)) {
-                exp = StringHelper.removeQuotes(value);
-            }
-            return SimpleExpressionBuilder.absExpression(exp);
+    @Override
+    public String createCode(CamelContext camelContext, String expression) 
throws SimpleParserException {
+        return BaseSimpleParser.CODE_START + doCreateCode(camelContext, 
expression) + BaseSimpleParser.CODE_END;
+    }
+
+    private String doCreateCode(CamelContext camelContext, String expression) 
throws SimpleParserException {
+        String function = getText();
+
+        // return the function directly if we can create function without 
analyzing the prefix
+        String answer = createCodeDirectly(function);
+        if (answer != null) {
+            return answer;
         }
-        // floor function
-        remainder = ifStartsWithReturnRemainder("floor(", function);
-        if (remainder != null) {
-            String exp = null;
-            String value = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(value)) {
-                exp = StringHelper.removeQuotes(value);
-            }
-            return SimpleExpressionBuilder.floorExpression(exp);
+
+        // exchange property first
+        answer = createCodeExchangeProperty(function);
+        if (answer != null) {
+            return answer;
         }
-        // ceil function
-        remainder = ifStartsWithReturnRemainder("ceil(", function);
-        if (remainder != null) {
-            String exp = null;
-            String value = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(value)) {
-                exp = StringHelper.removeQuotes(value);
-            }
-            return SimpleExpressionBuilder.ceilExpression(exp);
-        }
-        // sum function
-        remainder = ifStartsWithReturnRemainder("sum(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            String[] tokens = null;
-            if (ObjectHelper.isNotEmpty(values)) {
-                tokens = StringQuoteHelper.splitSafeQuote(values, ',', true, 
false);
-            }
-            return SimpleExpressionBuilder.sumExpression(tokens);
-        }
-        // max function
-        remainder = ifStartsWithReturnRemainder("max(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            String[] tokens = null;
-            if (ObjectHelper.isNotEmpty(values)) {
-                tokens = StringQuoteHelper.splitSafeQuote(values, ',', true, 
false);
-            }
-            return SimpleExpressionBuilder.maxExpression(tokens);
-        }
-        // min function
-        remainder = ifStartsWithReturnRemainder("min(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            String[] tokens = null;
-            if (ObjectHelper.isNotEmpty(values)) {
-                tokens = StringQuoteHelper.splitSafeQuote(values, ',', true, 
false);
-            }
-            return SimpleExpressionBuilder.minExpression(tokens);
-        }
-        // average function
-        remainder = ifStartsWithReturnRemainder("average(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            String[] tokens = null;
-            if (ObjectHelper.isNotEmpty(values)) {
-                tokens = StringQuoteHelper.splitSafeQuote(values, ',', true, 
false);
-            }
-            return SimpleExpressionBuilder.averageExpression(tokens);
-        }
-
-        return null;
-    }
-
-    @Deprecated(since = "4.21")
-    public static String ifStartsWithReturnRemainder(String prefix, String 
text) {
-        return SimpleFunctionHelper.ifStartsWithReturnRemainder(prefix, text);
-    }
-
-    @Override
-    public String createCode(CamelContext camelContext, String expression) 
throws SimpleParserException {
-        return BaseSimpleParser.CODE_START + doCreateCode(camelContext, 
expression) + BaseSimpleParser.CODE_END;
-    }
-
-    private String doCreateCode(CamelContext camelContext, String expression) 
throws SimpleParserException {
-        String function = getText();
-
-        // return the function directly if we can create function without 
analyzing the prefix
-        String answer = createCodeDirectly(function);
-        if (answer != null) {
-            return answer;
-        }
-
-        // exchange property first
-        answer = createCodeExchangeProperty(function);
-        if (answer != null) {
-            return answer;
-        }
-        // camelContext OGNL
-        String remainder = ifStartsWithReturnRemainder("camelContext", 
function);
+        // camelContext OGNL
+        String remainder = ifStartsWithReturnRemainder("camelContext", 
function);
         if (remainder != null) {
             boolean invalid = 
OgnlHelper.isInvalidValidOgnlExpression(remainder);
             if (invalid) {
@@ -1831,11 +1409,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
         if (misc != null) {
             return misc;
         }
-        // math functions
-        String math = createCodeExpressionMath(function);
-        if (math != null) {
-            return math;
-        }
 
         // code from external components (attachments, base64, ...)
         String external = 
SimpleFunctionDispatcher.tryCreateCodeExternal(camelContext, function, 
token.getIndex());
@@ -2132,142 +1705,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             return "Object value = " + exp + ";\n        return 
setVariable(exchange, " + name + ", " + type + ", value);";
         }
 
-        // substring function
-        remainder = ifStartsWithReturnRemainder("substring(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (values == null || ObjectHelper.isEmpty(values)) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${substring(num)}, 
${substring(num,num)} was: "
-                                                + function,
-                        token.getIndex());
-            }
-            String[] tokens = codeSplitSafe(values, ',', true, true);
-            if (tokens.length > 2) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${substring(num,num)} was: " + 
function, token.getIndex());
-            }
-            String num1 = tokens[0];
-            String num2 = "0";
-            if (tokens.length > 1) {
-                num2 = tokens[1];
-            }
-            num1 = num1.trim();
-            num2 = num2.trim();
-            return "substring(exchange, " + num1 + ", " + num2 + ")";
-        }
-        remainder = ifStartsWithReturnRemainder("substringBefore(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (values == null || ObjectHelper.isEmpty(values)) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${substringBefore(before)}, 
${substringBefore(exp,before)} was: "
-                                                + function,
-                        token.getIndex());
-            }
-            String[] tokens = codeSplitSafe(values, ',', true, true);
-            if (tokens.length > 2) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${substringBefore(before)}, 
${substringBefore(exp,before)} was: "
-                                                + function,
-                        token.getIndex());
-            }
-            // single quotes should be double quotes
-            for (int i = 0; i < tokens.length; i++) {
-                String s = tokens[i];
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                    tokens[i] = s;
-                }
-            }
-            String body = "body";
-            String before;
-            if (tokens.length > 1) {
-                body = tokens[0];
-                before = tokens[1];
-            } else {
-                before = tokens[0];
-            }
-            return "Object value = " + body + ";\n        Object before = " + 
before
-                   + ";\n        return substringBefore(exchange, value, 
before);";
-        }
-        remainder = ifStartsWithReturnRemainder("substringAfter(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (values == null || ObjectHelper.isEmpty(values)) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${substringAfter(before)}, 
${substringAfter(exp,before)} was: "
-                                                + function,
-                        token.getIndex());
-            }
-            String[] tokens = codeSplitSafe(values, ',', true, true);
-            if (tokens.length > 2) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${substringAfter(before)}, 
${substringAfter(exp,before)} was: "
-                                                + function,
-                        token.getIndex());
-            }
-            // single quotes should be double quotes
-            for (int i = 0; i < tokens.length; i++) {
-                String s = tokens[i];
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                    tokens[i] = s;
-                }
-            }
-            String body = "body";
-            String before;
-            if (tokens.length > 1) {
-                body = tokens[0];
-                before = tokens[1];
-            } else {
-                before = tokens[0];
-            }
-            return "Object value = " + body + ";\n        Object after = " + 
before
-                   + ";\n        return substringAfter(exchange, value, 
after);";
-        }
-        remainder = ifStartsWithReturnRemainder("substringBetween(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (values == null || ObjectHelper.isEmpty(values)) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${substringBetween(after,before)}, 
${substringBetween(exp,after,before)} was: "
-                                                + function,
-                        token.getIndex());
-            }
-            String[] tokens = codeSplitSafe(values, ',', true, true);
-            if (tokens.length < 2 || tokens.length > 3) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${substringBetween(after,before)}, 
${substringBetween(exp,after,before)} was: "
-                                                + function,
-                        token.getIndex());
-            }
-            // single quotes should be double quotes
-            for (int i = 0; i < tokens.length; i++) {
-                String s = tokens[i];
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                    tokens[i] = s;
-                }
-            }
-            String body = "body";
-            String after;
-            String before;
-            if (tokens.length == 3) {
-                body = tokens[0];
-                after = tokens[1];
-                before = tokens[2];
-            } else {
-                after = tokens[0];
-                before = tokens[1];
-            }
-            return "Object value = " + body + ";\n        Object after = " + 
after
-                   + ";\n        Object before = " + before
-                   + ";\n        return substringBetween(exchange, value, 
after, before);";
-        }
         // split function
         remainder = ifStartsWithReturnRemainder("split(", function);
         if (remainder != null) {
@@ -2313,45 +1750,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             throw new UnsupportedOperationException("filter is not supported 
in csimple language");
         }
 
-        // contains function
-        remainder = ifStartsWithReturnRemainder("contains(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (values == null || ObjectHelper.isEmpty(values)) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${contains(text)} or 
${contains(exp,text)} was: "
-                                                + function,
-                        token.getIndex());
-            }
-            String[] tokens = codeSplitSafe(values, ',', true, true);
-            if (tokens.length < 1 || tokens.length > 2) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${contains(text)} or 
${contains(exp,text)} was: "
-                                                + function,
-                        token.getIndex());
-            }
-            // single quotes should be double quotes
-            for (int i = 0; i < tokens.length; i++) {
-                String s = tokens[i];
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                    tokens[i] = s;
-                }
-            }
-            String exp = "body";
-            String pattern;
-            if (tokens.length == 1) {
-                pattern = tokens[0];
-            } else {
-                exp = tokens[0];
-                pattern = tokens[1];
-            }
-            pattern = StringHelper.removeLeadingAndEndingQuotes(pattern);
-            pattern = StringQuoteHelper.doubleQuote(pattern);
-            return "Object value = " + exp + ";\n        return 
containsIgnoreCase(exchange, value, " + pattern + ");";
-        }
-
         remainder = ifStartsWithReturnRemainder("range(", function);
         if (remainder != null) {
             String values = StringHelper.beforeLast(remainder, ")");
@@ -2373,37 +1771,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             }
         }
 
-        // replace function
-        remainder = ifStartsWithReturnRemainder("replace(", function);
-        if (remainder != null) {
-            String values = StringHelper.before(remainder, ")");
-            if (values == null || ObjectHelper.isEmpty(values)) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${replace(from,to)} was: " + function,
-                        token.getIndex());
-            }
-            String[] tokens = codeSplitSafe(values, ',', true, false);
-            if (tokens.length > 2) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${replace(from,to)} was: " + function, 
token.getIndex());
-            }
-            String from = StringHelper.xmlDecode(tokens[0]);
-            String to = StringHelper.xmlDecode(tokens[1]);
-            // special to make it easy to replace to an empty value (ie remove)
-            if ("&empty;".equals(to)) {
-                to = "";
-            }
-            if ("\"".equals(from)) {
-                from = "\\\"";
-            }
-            if ("\"".equals(to)) {
-                to = "\\\"";
-            }
-            from = StringQuoteHelper.doubleQuote(from);
-            to = StringQuoteHelper.doubleQuote(to);
-            return "replace(exchange, " + from + ", " + to + ")";
-        }
-
         // distinct function
         remainder = ifStartsWithReturnRemainder("distinct(", function);
         if (remainder != null) {
@@ -2468,42 +1835,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             return "shuffle(exchange, " + p + ")";
         }
 
-        // pad function
-        remainder = ifStartsWithReturnRemainder("pad(", function);
-        if (remainder != null) {
-            String separator = null;
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (values == null || ObjectHelper.isEmpty(values)) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${pad(len)} or ${pad(exp,len)} or 
${pad(exp,len,separator)} was: " + function,
-                        token.getIndex());
-            }
-            String[] tokens = codeSplitSafe(values, ',', true, true);
-            if (tokens.length < 2 || tokens.length > 3) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${pad(exp,len)} or 
${pad(exp,len,separator)} was: " + function,
-                        token.getIndex());
-            }
-            // single quotes should be double quotes
-            for (int i = 0; i < tokens.length; i++) {
-                String s = tokens[i];
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                    tokens[i] = s;
-                }
-            }
-            if (tokens.length == 3) {
-                separator = tokens[2];
-            }
-            // separator must be in double quotes
-            separator = StringHelper.removeLeadingAndEndingQuotes(separator);
-            separator = separator != null ? 
StringQuoteHelper.doubleQuote(separator) : "null";
-            return "Object value = " + tokens[0] + ";\n        " + "Object 
width = " + tokens[1]
-                   + ";\n        String separator = " + separator
-                   + ";\n        return pad(exchange, value, width, 
separator);";
-        }
-
         // kindOfType function
         remainder = ifStartsWithReturnRemainder("kindOfType(", function);
         if (remainder != null) {
@@ -2529,8 +1860,8 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             return "Object o = " + exp + ";\n        return 
kindOfType(exchange, o);";
         }
 
-        // quote function
-        remainder = ifStartsWithReturnRemainder("quote(", function);
+        // isEmpty function
+        remainder = ifStartsWithReturnRemainder("isEmpty(", function);
         if (remainder != null) {
             String exp = null;
             String values = StringHelper.beforeLast(remainder, ")");
@@ -2538,7 +1869,7 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
                 String[] tokens = codeSplitSafe(values, ',', true, true);
                 if (tokens.length != 1) {
                     throw new SimpleParserException(
-                            "Valid syntax: ${quote(exp)} was: " + function, 
token.getIndex());
+                            "Valid syntax: ${isEmpty(exp)} was: " + function, 
token.getIndex());
                 }
                 // single quotes should be double quotes
                 String s = tokens[0];
@@ -2549,12 +1880,13 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
                 exp = s;
             }
             if (ObjectHelper.isEmpty(exp)) {
-                exp = "null";
+                exp = "body";
             }
-            return "Object o = " + exp + ";\n        return quote(exchange, 
o);";
+            return "Object o = " + exp + ";\n        return isEmpty(exchange, 
o);";
         }
-        // safaeQuote function
-        remainder = ifStartsWithReturnRemainder("safeQuote(", function);
+
+        // isNumeric function
+        remainder = ifStartsWithReturnRemainder("isAlpha(", function);
         if (remainder != null) {
             String exp = null;
             String values = StringHelper.beforeLast(remainder, ")");
@@ -2562,7 +1894,7 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
                 String[] tokens = codeSplitSafe(values, ',', true, true);
                 if (tokens.length != 1) {
                     throw new SimpleParserException(
-                            "Valid syntax: ${safeQuote(exp)} was: " + 
function, token.getIndex());
+                            "Valid syntax: ${isAlpha(exp)} was: " + function, 
token.getIndex());
                 }
                 // single quotes should be double quotes
                 String s = tokens[0];
@@ -2575,10 +1907,10 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             if (ObjectHelper.isEmpty(exp)) {
                 exp = "body";
             }
-            return "Object o = " + exp + ";\n        return 
safeQuote(exchange, o);";
+            return "Object o = " + exp + ";\n        return isAlpha(exchange, 
o);";
         }
-        // unquote function
-        remainder = ifStartsWithReturnRemainder("unquote(", function);
+        // isAlphaNumeric function
+        remainder = ifStartsWithReturnRemainder("isAlphaNumeric(", function);
         if (remainder != null) {
             String exp = null;
             String values = StringHelper.beforeLast(remainder, ")");
@@ -2586,27 +1918,23 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
                 String[] tokens = codeSplitSafe(values, ',', true, true);
                 if (tokens.length != 1) {
                     throw new SimpleParserException(
-                            "Valid syntax: ${unquote(exp)} was: " + function, 
token.getIndex());
+                            "Valid syntax: ${isAlphaNumeric(exp)} was: " + 
function, token.getIndex());
                 }
                 // single quotes should be double quotes
                 String s = tokens[0];
                 if (StringHelper.isSingleQuoted(s)) {
                     s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    // need to escape double quotes
-                    s = s.replace("\"", "\\\"");
-                    // and enclose in a string
                     s = StringQuoteHelper.doubleQuote(s);
                 }
                 exp = s;
             }
             if (ObjectHelper.isEmpty(exp)) {
-                exp = "null";
+                exp = "body";
             }
-            return "Object o = " + exp + ";\n        return unquote(exchange, 
o);";
+            return "Object o = " + exp + ";\n        return 
isAlphaNumeric(exchange, o);";
         }
-
-        // trim function
-        remainder = ifStartsWithReturnRemainder("trim(", function);
+        // isNumeric function
+        remainder = ifStartsWithReturnRemainder("isNumeric(", function);
         if (remainder != null) {
             String exp = null;
             String values = StringHelper.beforeLast(remainder, ")");
@@ -2614,7 +1942,7 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
                 String[] tokens = codeSplitSafe(values, ',', true, true);
                 if (tokens.length != 1) {
                     throw new SimpleParserException(
-                            "Valid syntax: ${trim(exp)} was: " + function, 
token.getIndex());
+                            "Valid syntax: ${isNumeric(exp)} was: " + 
function, token.getIndex());
                 }
                 // single quotes should be double quotes
                 String s = tokens[0];
@@ -2625,127 +1953,14 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
                 exp = s;
             }
             if (ObjectHelper.isEmpty(exp)) {
-                exp = "null";
-            }
-            return "Object o = " + exp + ";\n        return trim(exchange, 
o);";
-        }
-
-        // val function
-        remainder = ifStartsWithReturnRemainder("val(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (values == null || ObjectHelper.isEmpty(values)) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${val(exp)} was: " + function,
-                        token.getIndex());
+                exp = "body";
             }
-            String s = values;
-            s = StringHelper.removeLeadingAndEndingQuotes(s);
-            s = StringQuoteHelper.doubleQuote(s);
-            return "Object o = " + s + ";\n        return o;";
+            return "Object o = " + exp + ";\n        return 
isNumeric(exchange, o);";
         }
-
-        // isEmpty function
-        remainder = ifStartsWithReturnRemainder("isEmpty(", function);
+        // not function
+        remainder = ifStartsWithReturnRemainder("not(", function);
         if (remainder != null) {
-            String exp = null;
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(values)) {
-                String[] tokens = codeSplitSafe(values, ',', true, true);
-                if (tokens.length != 1) {
-                    throw new SimpleParserException(
-                            "Valid syntax: ${isEmpty(exp)} was: " + function, 
token.getIndex());
-                }
-                // single quotes should be double quotes
-                String s = tokens[0];
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                }
-                exp = s;
-            }
-            if (ObjectHelper.isEmpty(exp)) {
-                exp = "body";
-            }
-            return "Object o = " + exp + ";\n        return isEmpty(exchange, 
o);";
-        }
-
-        // isNumeric function
-        remainder = ifStartsWithReturnRemainder("isAlpha(", function);
-        if (remainder != null) {
-            String exp = null;
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(values)) {
-                String[] tokens = codeSplitSafe(values, ',', true, true);
-                if (tokens.length != 1) {
-                    throw new SimpleParserException(
-                            "Valid syntax: ${isAlpha(exp)} was: " + function, 
token.getIndex());
-                }
-                // single quotes should be double quotes
-                String s = tokens[0];
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                }
-                exp = s;
-            }
-            if (ObjectHelper.isEmpty(exp)) {
-                exp = "body";
-            }
-            return "Object o = " + exp + ";\n        return isAlpha(exchange, 
o);";
-        }
-        // isAlphaNumeric function
-        remainder = ifStartsWithReturnRemainder("isAlphaNumeric(", function);
-        if (remainder != null) {
-            String exp = null;
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(values)) {
-                String[] tokens = codeSplitSafe(values, ',', true, true);
-                if (tokens.length != 1) {
-                    throw new SimpleParserException(
-                            "Valid syntax: ${isAlphaNumeric(exp)} was: " + 
function, token.getIndex());
-                }
-                // single quotes should be double quotes
-                String s = tokens[0];
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                }
-                exp = s;
-            }
-            if (ObjectHelper.isEmpty(exp)) {
-                exp = "body";
-            }
-            return "Object o = " + exp + ";\n        return 
isAlphaNumeric(exchange, o);";
-        }
-        // isNumeric function
-        remainder = ifStartsWithReturnRemainder("isNumeric(", function);
-        if (remainder != null) {
-            String exp = null;
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(values)) {
-                String[] tokens = codeSplitSafe(values, ',', true, true);
-                if (tokens.length != 1) {
-                    throw new SimpleParserException(
-                            "Valid syntax: ${isNumeric(exp)} was: " + 
function, token.getIndex());
-                }
-                // single quotes should be double quotes
-                String s = tokens[0];
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                }
-                exp = s;
-            }
-            if (ObjectHelper.isEmpty(exp)) {
-                exp = "body";
-            }
-            return "Object o = " + exp + ";\n        return 
isNumeric(exchange, o);";
-        }
-        // not function
-        remainder = ifStartsWithReturnRemainder("not(", function);
-        if (remainder != null) {
-            String exp = "body";
+            String exp = "body";
             String values = StringHelper.beforeLast(remainder, ")");
             if (ObjectHelper.isNotEmpty(values)) {
                 String[] tokens = codeSplitSafe(values, ',', true, true);
@@ -2762,79 +1977,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             return "Object o = " + exp + ";\n        return isNot(exchange, 
o);";
         }
 
-        // capitalize function
-        remainder = ifStartsWithReturnRemainder("capitalize(", function);
-        if (remainder != null) {
-            String exp = null;
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(values)) {
-                String[] tokens = codeSplitSafe(values, ',', true, true);
-                if (tokens.length != 1) {
-                    throw new SimpleParserException(
-                            "Valid syntax: ${capitalize(exp)} was: " + 
function, token.getIndex());
-                }
-                // single quotes should be double quotes
-                String s = tokens[0];
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                }
-                exp = s;
-            }
-            if (ObjectHelper.isEmpty(exp)) {
-                exp = "null";
-            }
-            return "Object o = " + exp + ";\n        return 
capitalize(exchange, o);";
-        }
-
-        // concat function
-        remainder = ifStartsWithReturnRemainder("concat(", function);
-        if (remainder != null) {
-            String separator = "null";
-            String exp1 = "body";
-            String exp2;
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (values == null || ObjectHelper.isEmpty(values)) {
-                throw new SimpleParserException(
-                        "Valid syntax: ${concat(exp)} or ${concat(exp,exp)} or 
${concat(exp,exp,separator)} was: " + function,
-                        token.getIndex());
-            }
-            if (values.contains(",")) {
-                String[] tokens = codeSplitSafe(values, ',', true, true);
-                if (tokens.length > 3) {
-                    throw new SimpleParserException(
-                            "Valid syntax: ${concat(exp)} or 
${concat(exp,exp)} or ${concat(exp,exp,separator)} was: "
-                                                    + function,
-                            token.getIndex());
-                }
-                // single quotes should be double quotes
-                for (int i = 0; i < tokens.length; i++) {
-                    String s = tokens[i];
-                    if (StringHelper.isSingleQuoted(s)) {
-                        s = StringHelper.removeLeadingAndEndingQuotes(s);
-                        s = StringQuoteHelper.doubleQuote(s);
-                        tokens[i] = s;
-                    }
-                }
-                if (tokens.length == 1) {
-                    exp2 = tokens[0];
-                } else {
-                    exp1 = tokens[0];
-                    exp2 = tokens[1];
-                }
-                if (tokens.length == 3) {
-                    separator = tokens[2];
-                }
-            } else {
-                String s = values.trim();
-                s = StringHelper.removeLeadingAndEndingQuotes(s);
-                s = StringQuoteHelper.doubleQuote(s);
-                exp2 = s;
-            }
-            return "Object right = " + exp2 + ";\n        Object left = " + 
exp1 + ";\n        " + "Object separator = "
-                   + separator + ";\n        return concat(exchange, left, 
right, separator);";
-        }
-
         // convertTo function
         remainder = ifStartsWithReturnRemainder("convertTo(", function);
         if (remainder != null) {
@@ -2921,128 +2063,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             throw new UnsupportedOperationException("assertExpression is not 
supported in csimple language");
         }
 
-        // uppercase function
-        remainder = ifStartsWithReturnRemainder("uppercase(", function);
-        if (remainder != null) {
-            String exp = null;
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(values)) {
-                String[] tokens = codeSplitSafe(values, ',', true, true);
-                if (tokens.length != 1) {
-                    throw new SimpleParserException(
-                            "Valid syntax: ${uppercase(exp)} was: " + 
function, token.getIndex());
-                }
-                // single quotes should be double quotes
-                String s = tokens[0];
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                }
-                exp = s;
-            }
-            if (ObjectHelper.isEmpty(exp)) {
-                exp = "null";
-            }
-            return "Object o = " + exp + ";\n        return 
uppercase(exchange, o);";
-        }
-        // lowercase
-        remainder = ifStartsWithReturnRemainder("lowercase(", function);
-        if (remainder != null) {
-            String exp = null;
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(values)) {
-                String[] tokens = codeSplitSafe(values, ',', true, true);
-                if (tokens.length != 1) {
-                    throw new SimpleParserException(
-                            "Valid syntax: ${lowercase(exp)} was: " + 
function, token.getIndex());
-                }
-                // single quotes should be double quotes
-                String s = tokens[0];
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                }
-                exp = s;
-            }
-            if (ObjectHelper.isEmpty(exp)) {
-                exp = "null";
-            }
-            return "Object o = " + exp + ";\n        return 
lowercase(exchange, o);";
-        }
-
-        // length function
-        remainder = ifStartsWithReturnRemainder("length(", function);
-        if (remainder != null) {
-            String exp = null;
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(values)) {
-                String[] tokens = codeSplitSafe(values, ',', true, true);
-                if (tokens.length != 1) {
-                    throw new SimpleParserException(
-                            "Valid syntax: ${length(exp)} was: " + function, 
token.getIndex());
-                }
-                // single quotes should be double quotes
-                String s = tokens[0];
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                }
-                exp = s;
-            }
-            if (ObjectHelper.isEmpty(exp)) {
-                exp = "body";
-            }
-            return "Object o = " + exp + ";\n        return length(exchange, 
o);";
-        }
-        // size function
-        remainder = ifStartsWithReturnRemainder("size(", function);
-        if (remainder != null) {
-            String exp = null;
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(values)) {
-                String[] tokens = codeSplitSafe(values, ',', true, true);
-                if (tokens.length != 1) {
-                    throw new SimpleParserException(
-                            "Valid syntax: ${size(exp)} was: " + function, 
token.getIndex());
-                }
-                // single quotes should be double quotes
-                String s = tokens[0];
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                }
-                exp = s;
-            }
-            if (ObjectHelper.isEmpty(exp)) {
-                exp = "body";
-            }
-            return "Object o = " + exp + ";\n        return size(exchange, 
o);";
-        }
-        // normalizeWhitespace function
-        remainder = ifStartsWithReturnRemainder("normalizeWhitespace(", 
function);
-        if (remainder != null) {
-            String exp = null;
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(values)) {
-                String[] tokens = codeSplitSafe(values, ',', true, true);
-                if (tokens.length != 1) {
-                    throw new SimpleParserException(
-                            "Valid syntax: ${normalizeWhitespace(exp)} was: " 
+ function, token.getIndex());
-                }
-                // single quotes should be double quotes
-                String s = tokens[0];
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                }
-                exp = s;
-            }
-            if (ObjectHelper.isEmpty(exp)) {
-                exp = "null";
-            }
-            return "Object o = " + exp + ";\n        return 
normalizeWhitespace(exchange, o);";
-        }
-
         // messageHistory function
         remainder = ifStartsWithReturnRemainder("messageHistory", function);
         if (remainder != null) {
@@ -3259,343 +2279,14 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
         return null;
     }
 
-    private static List<String> splitOgnl(String remainder) {
-        List<String> methods = OgnlHelper.splitOgnl(remainder);
-        // if its a double index [foo][0] then we want them combined into a 
single element
-        List<String> answer = new ArrayList<>();
-        for (String m : methods) {
-            if (m.startsWith(".")) {
-                m = m.substring(1);
-            }
-            boolean index = m.startsWith("[") && m.endsWith("]");
-            if (index) {
-                String last = answer.isEmpty() ? null : 
answer.get(answer.size() - 1);
-                boolean lastIndex = last != null && last.startsWith("[") && 
last.endsWith("]");
-                if (lastIndex) {
-                    String line = last + m;
-                    answer.set(answer.size() - 1, line);
-                } else {
-                    answer.add(m);
-                }
-            } else {
-                answer.add(m);
-            }
-        }
-
-        return answer;
-    }
-
-    private String createCodeExpressionMath(String function) {
-        String remainder;
-
-        // sum function
-        remainder = ifStartsWithReturnRemainder("sum(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            String[] tokens = null;
-            if (ObjectHelper.isNotEmpty(values)) {
-                tokens = codeSplitSafe(values, ',', true, true);
-            }
-            StringJoiner sj = new StringJoiner(", ");
-            for (int i = 0; tokens != null && i < tokens.length; i++) {
-                String s = tokens[i];
-                // single quotes should be double quotes
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                }
-                sj.add(s);
-            }
-            String p = sj.length() > 0 ? sj.toString() : "null";
-            return "sum(exchange, " + p + ")";
-        }
-        // abs function
-        remainder = ifStartsWithReturnRemainder("abs(", function);
-        if (remainder != null) {
-            String exp = null;
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(values)) {
-                String[] tokens = codeSplitSafe(values, ',', true, true);
-                if (tokens.length != 1) {
-                    throw new SimpleParserException(
-                            "Valid syntax: ${abs(exp)} was: " + function, 
token.getIndex());
-                }
-                // single quotes should be double quotes
-                String s = tokens[0];
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                }
-                exp = s;
-            }
-            if (ObjectHelper.isEmpty(exp)) {
-                exp = "null";
-            }
-            return "Object o = " + exp + ";\n        return abs(exchange, o);";
-        }
-        // floor function
-        remainder = ifStartsWithReturnRemainder("floor(", function);
-        if (remainder != null) {
-            String exp = null;
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(values)) {
-                String[] tokens = codeSplitSafe(values, ',', true, true);
-                if (tokens.length != 1) {
-                    throw new SimpleParserException(
-                            "Valid syntax: ${floor(exp)} was: " + function, 
token.getIndex());
-                }
-                // single quotes should be double quotes
-                String s = tokens[0];
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                }
-                exp = s;
-            }
-            if (ObjectHelper.isEmpty(exp)) {
-                exp = "null";
-            }
-            return "Object o = " + exp + ";\n        return floor(exchange, 
o);";
-        }
-        remainder = ifStartsWithReturnRemainder("ceil(", function);
-        if (remainder != null) {
-            String exp = null;
-            String values = StringHelper.beforeLast(remainder, ")");
-            if (ObjectHelper.isNotEmpty(values)) {
-                String[] tokens = codeSplitSafe(values, ',', true, true);
-                if (tokens.length != 1) {
-                    throw new SimpleParserException(
-                            "Valid syntax: ${ceil(exp)} was: " + function, 
token.getIndex());
-                }
-                // single quotes should be double quotes
-                String s = tokens[0];
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                }
-                exp = s;
-            }
-            if (ObjectHelper.isEmpty(exp)) {
-                exp = "null";
-            }
-            return "Object o = " + exp + ";\n        return ceil(exchange, 
o);";
-        }
-
-        // max function
-        remainder = ifStartsWithReturnRemainder("max(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            String[] tokens = null;
-            if (ObjectHelper.isNotEmpty(values)) {
-                tokens = codeSplitSafe(values, ',', true, true);
-            }
-            StringJoiner sj = new StringJoiner(", ");
-            for (int i = 0; tokens != null && i < tokens.length; i++) {
-                String s = tokens[i];
-                // single quotes should be double quotes
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                }
-                sj.add(s);
-            }
-            String p = sj.length() > 0 ? sj.toString() : "null";
-            return "max(exchange, " + p + ")";
-        }
-        // min function
-        remainder = ifStartsWithReturnRemainder("min(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            String[] tokens = null;
-            if (ObjectHelper.isNotEmpty(values)) {
-                tokens = codeSplitSafe(values, ',', true, true);
-            }
-            StringJoiner sj = new StringJoiner(", ");
-            for (int i = 0; tokens != null && i < tokens.length; i++) {
-                String s = tokens[i];
-                // single quotes should be double quotes
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                }
-                sj.add(s);
-            }
-            String p = sj.length() > 0 ? sj.toString() : "null";
-            return "min(exchange, " + p + ")";
-        }
-        // average function
-        remainder = ifStartsWithReturnRemainder("average(", function);
-        if (remainder != null) {
-            String values = StringHelper.beforeLast(remainder, ")");
-            String[] tokens = null;
-            if (ObjectHelper.isNotEmpty(values)) {
-                tokens = codeSplitSafe(values, ',', true, true);
-            }
-            StringJoiner sj = new StringJoiner(", ");
-            for (int i = 0; tokens != null && i < tokens.length; i++) {
-                String s = tokens[i];
-                // single quotes should be double quotes
-                if (StringHelper.isSingleQuoted(s)) {
-                    s = StringHelper.removeLeadingAndEndingQuotes(s);
-                    s = StringQuoteHelper.doubleQuote(s);
-                }
-                sj.add(s);
-            }
-            String p = sj.length() > 0 ? sj.toString() : "null";
-            return "average(exchange, " + p + ")";
-        }
-
-        return null;
-    }
-
     @Deprecated(since = "4.21")
     public static String ognlCodeMethods(String remainder, String type) {
         return SimpleFunctionHelper.ognlCodeMethods(remainder, type);
     }
 
+    @Deprecated(since = "4.21")
     public static String[] codeSplitSafe(String input, char separator, boolean 
trim, boolean keepQuotes) {
-        if (input == null) {
-            return null;
-        }
-
-        if (input.indexOf(separator) == -1) {
-            if (input.length() > 1) {
-                char ch = input.charAt(0);
-                char ch2 = input.charAt(input.length() - 1);
-                boolean singleQuoted = ch == '\'' && ch2 == '\'';
-                boolean doubleQuoted = ch == '"' && ch2 == '"';
-                if (!keepQuotes && (singleQuoted || doubleQuoted)) {
-                    input = input.substring(1, input.length() - 1);
-                    // do not trim quoted text
-                } else if (trim) {
-                    input = input.trim();
-                }
-            }
-            // no separator in data, so return single string with input as is
-            return new String[] { input };
-        }
-
-        List<String> answer = new ArrayList<>();
-        StringBuilder sb = new StringBuilder(256);
-
-        int codeLevel = 0;
-        boolean singleQuoted = false;
-        boolean doubleQuoted = false;
-        boolean separating = false;
-
-        for (int i = 0; i < input.length(); i++) {
-            char ch = input.charAt(i);
-            char prev = i > 0 ? input.charAt(i - 1) : 0;
-            boolean isQuoting = singleQuoted || doubleQuoted;
-            boolean last = i == input.length() - 1;
-
-            // do not split inside code blocks
-            if (input.indexOf(BaseSimpleParser.CODE_START, i) == i) {
-                codeLevel++;
-                sb.append(BaseSimpleParser.CODE_START);
-                i = i + BaseSimpleParser.CODE_START.length() - 1;
-                continue;
-            } else if (input.indexOf(BaseSimpleParser.CODE_END, i) == i) {
-                codeLevel--;
-                sb.append(BaseSimpleParser.CODE_END);
-                i = i + BaseSimpleParser.CODE_END.length() - 1;
-                continue;
-            }
-            if (codeLevel > 0) {
-                sb.append(ch);
-                continue;
-            }
-
-            if (!doubleQuoted && ch == '\'') {
-                if (singleQuoted && prev == ch && sb.isEmpty()) {
-                    // its an empty quote so add empty text
-                    if (keepQuotes) {
-                        answer.add("''");
-                    } else {
-                        answer.add("");
-                    }
-                }
-                // special logic needed if this quote is the end
-                if (last) {
-                    if (singleQuoted && !sb.isEmpty()) {
-                        String text = sb.toString();
-                        // do not trim a quoted string
-                        if (keepQuotes) {
-                            answer.add(text + "'"); // append ending quote
-                        } else {
-                            answer.add(text);
-                        }
-                        sb.setLength(0);
-                    }
-                    break; // break out as we are finished
-                }
-                singleQuoted = !singleQuoted;
-                if (keepQuotes) {
-                    sb.append(ch);
-                }
-                continue;
-            } else if (!singleQuoted && ch == '"') {
-                if (doubleQuoted && prev == ch && sb.isEmpty()) {
-                    // its an empty quote so add empty text
-                    if (keepQuotes) {
-                        answer.add("\""); // append ending quote
-                    } else {
-                        answer.add("");
-                    }
-                }
-                // special logic needed if this quote is the end
-                if (last) {
-                    if (doubleQuoted && !sb.isEmpty()) {
-                        String text = sb.toString();
-                        // do not trim a quoted string
-                        if (keepQuotes) {
-                            answer.add(text + "\"");
-                        } else {
-                            answer.add(text);
-                        }
-                        sb.setLength(0);
-                    }
-                    break; // break out as we are finished
-                }
-                doubleQuoted = !doubleQuoted;
-                if (keepQuotes) {
-                    sb.append(ch);
-                }
-                continue;
-            } else if (!isQuoting && ch == separator) {
-                separating = true;
-                // add as answer if we are not in a quote
-                if (!sb.isEmpty()) {
-                    String text = sb.toString();
-                    if (trim) {
-                        text = text.trim();
-                    }
-                    answer.add(text);
-                    sb.setLength(0);
-                }
-                // we should avoid adding the separator
-                continue;
-            }
-
-            if (trim && !isQuoting && separating && separator != ' ' && ch == 
' ') {
-                continue;
-            }
-            separating = false;
-
-            // append char
-            sb.append(ch);
-        }
-
-        // any leftover
-        if (!sb.isEmpty()) {
-            String text = sb.toString();
-            if (trim) {
-                text = text.trim();
-            }
-            answer.add(text);
-        }
-
-        return answer.toArray(new String[0]);
+        return SimpleFunctionHelper.codeSplitSafe(input, separator, trim, 
keepQuotes);
     }
 
 }
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/MathFunctionFactory.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/MathFunctionFactory.java
new file mode 100644
index 000000000000..bbd3e1e97f4f
--- /dev/null
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/MathFunctionFactory.java
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.language.simple.functions;
+
+import java.util.StringJoiner;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Expression;
+import org.apache.camel.language.simple.SimpleExpressionBuilder;
+import org.apache.camel.language.simple.types.SimpleParserException;
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.StringHelper;
+import org.apache.camel.util.StringQuoteHelper;
+
+import static 
org.apache.camel.language.simple.SimpleFunctionHelper.codeSplitSafe;
+import static 
org.apache.camel.language.simple.SimpleFunctionHelper.ifStartsWithReturnRemainder;
+
+/**
+ * Built-in Simple math functions: {@code ${abs}}, {@code ${floor}}, {@code 
${ceil}}, {@code ${sum}}, {@code ${max}},
+ * {@code ${min}}, {@code ${average}}.
+ */
+public final class MathFunctionFactory implements 
SimpleLanguageFunctionFactory {
+
+    @Override
+    public Expression createFunction(CamelContext camelContext, String 
function, int index) {
+        String remainder;
+
+        remainder = ifStartsWithReturnRemainder("abs(", function);
+        if (remainder != null) {
+            String value = StringHelper.beforeLast(remainder, ")");
+            return SimpleExpressionBuilder
+                    .absExpression(ObjectHelper.isNotEmpty(value) ? 
StringHelper.removeQuotes(value) : null);
+        }
+        remainder = ifStartsWithReturnRemainder("floor(", function);
+        if (remainder != null) {
+            String value = StringHelper.beforeLast(remainder, ")");
+            return SimpleExpressionBuilder.floorExpression(
+                    ObjectHelper.isNotEmpty(value) ? 
StringHelper.removeQuotes(value) : null);
+        }
+        remainder = ifStartsWithReturnRemainder("ceil(", function);
+        if (remainder != null) {
+            String value = StringHelper.beforeLast(remainder, ")");
+            return SimpleExpressionBuilder.ceilExpression(
+                    ObjectHelper.isNotEmpty(value) ? 
StringHelper.removeQuotes(value) : null);
+        }
+        remainder = ifStartsWithReturnRemainder("sum(", function);
+        if (remainder != null) {
+            return 
SimpleExpressionBuilder.sumExpression(parseVariadicTokens(remainder));
+        }
+        remainder = ifStartsWithReturnRemainder("max(", function);
+        if (remainder != null) {
+            return 
SimpleExpressionBuilder.maxExpression(parseVariadicTokens(remainder));
+        }
+        remainder = ifStartsWithReturnRemainder("min(", function);
+        if (remainder != null) {
+            return 
SimpleExpressionBuilder.minExpression(parseVariadicTokens(remainder));
+        }
+        remainder = ifStartsWithReturnRemainder("average(", function);
+        if (remainder != null) {
+            return 
SimpleExpressionBuilder.averageExpression(parseVariadicTokens(remainder));
+        }
+
+        return null;
+    }
+
+    @Override
+    public String createCode(CamelContext camelContext, String function, int 
index) {
+        String remainder;
+
+        remainder = ifStartsWithReturnRemainder("sum(", function);
+        if (remainder != null) {
+            return codeVariadic("sum", remainder);
+        }
+        remainder = ifStartsWithReturnRemainder("abs(", function);
+        if (remainder != null) {
+            return codeUnary("abs", remainder, function, index);
+        }
+        remainder = ifStartsWithReturnRemainder("floor(", function);
+        if (remainder != null) {
+            return codeUnary("floor", remainder, function, index);
+        }
+        remainder = ifStartsWithReturnRemainder("ceil(", function);
+        if (remainder != null) {
+            return codeUnary("ceil", remainder, function, index);
+        }
+        remainder = ifStartsWithReturnRemainder("max(", function);
+        if (remainder != null) {
+            return codeVariadic("max", remainder);
+        }
+        remainder = ifStartsWithReturnRemainder("min(", function);
+        if (remainder != null) {
+            return codeVariadic("min", remainder);
+        }
+        remainder = ifStartsWithReturnRemainder("average(", function);
+        if (remainder != null) {
+            return codeVariadic("average", remainder);
+        }
+
+        return null;
+    }
+
+    private static String[] parseVariadicTokens(String remainder) {
+        String values = StringHelper.beforeLast(remainder, ")");
+        if (ObjectHelper.isNotEmpty(values)) {
+            return StringQuoteHelper.splitSafeQuote(values, ',', true, false);
+        }
+        return null;
+    }
+
+    private static String codeUnary(String name, String remainder, String 
function, int index) {
+        String exp = null;
+        String values = StringHelper.beforeLast(remainder, ")");
+        if (ObjectHelper.isNotEmpty(values)) {
+            String[] tokens = codeSplitSafe(values, ',', true, true);
+            if (tokens.length != 1) {
+                throw new SimpleParserException("Valid syntax: ${" + name + 
"(exp)} was: " + function, index);
+            }
+            String s = tokens[0];
+            if (StringHelper.isSingleQuoted(s)) {
+                s = StringHelper.removeLeadingAndEndingQuotes(s);
+                s = StringQuoteHelper.doubleQuote(s);
+            }
+            exp = s;
+        }
+        if (ObjectHelper.isEmpty(exp)) {
+            exp = "null";
+        }
+        return "Object o = " + exp + ";\n        return " + name + "(exchange, 
o);";
+    }
+
+    private static String codeVariadic(String name, String remainder) {
+        String values = StringHelper.beforeLast(remainder, ")");
+        String[] tokens = null;
+        if (ObjectHelper.isNotEmpty(values)) {
+            tokens = codeSplitSafe(values, ',', true, true);
+        }
+        StringJoiner sj = new StringJoiner(", ");
+        for (int i = 0; tokens != null && i < tokens.length; i++) {
+            String s = tokens[i];
+            if (StringHelper.isSingleQuoted(s)) {
+                s = StringHelper.removeLeadingAndEndingQuotes(s);
+                s = StringQuoteHelper.doubleQuote(s);
+            }
+            sj.add(s);
+        }
+        String p = sj.length() > 0 ? sj.toString() : "null";
+        return name + "(exchange, " + p + ")";
+    }
+}
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/StringFunctionFactory.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/StringFunctionFactory.java
new file mode 100644
index 000000000000..442c9be46086
--- /dev/null
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/StringFunctionFactory.java
@@ -0,0 +1,687 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.language.simple.functions;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Expression;
+import org.apache.camel.language.simple.SimpleExpressionBuilder;
+import org.apache.camel.language.simple.types.SimpleParserException;
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+import org.apache.camel.support.builder.ExpressionBuilder;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.StringHelper;
+import org.apache.camel.util.StringQuoteHelper;
+
+import static 
org.apache.camel.language.simple.SimpleFunctionHelper.codeSplitSafe;
+import static 
org.apache.camel.language.simple.SimpleFunctionHelper.ifStartsWithReturnRemainder;
+
+/**
+ * Built-in Simple string functions: {@code ${replace}}, {@code ${substring}}, 
{@code ${substringBefore}},
+ * {@code ${substringAfter}}, {@code ${substringBetween}}, {@code 
${contains}}, {@code ${trim}}, {@code ${val}},
+ * {@code ${capitalize}}, {@code ${pad}}, {@code ${concat}}, {@code ${quote}}, 
{@code ${safeQuote}}, {@code ${unquote}},
+ * {@code ${uppercase}}, {@code ${lowercase}}, {@code ${length}}, {@code 
${size}}, {@code ${normalizeWhitespace}}.
+ */
+public final class StringFunctionFactory implements 
SimpleLanguageFunctionFactory {
+
+    @Override
+    public Expression createFunction(CamelContext camelContext, String 
function, int index) {
+        String remainder;
+
+        remainder = ifStartsWithReturnRemainder("replace(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${replace(from,to)} or 
${replace(from,to,expression)} was: " + function, index);
+            }
+            String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',', 
false);
+            if (tokens.length > 3) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${replace(from,to,expression)} was: " + 
function, index);
+            }
+            String from = StringHelper.xmlDecode(tokens[0]);
+            String to = StringHelper.xmlDecode(tokens[1]);
+            if ("&empty;".equals(to)) {
+                to = "";
+            }
+            String exp = "${body}";
+            if (tokens.length == 3) {
+                exp = tokens[2];
+            }
+            return SimpleExpressionBuilder.replaceExpression(exp, from, to);
+        }
+
+        remainder = ifStartsWithReturnRemainder("substring(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${substring(num)}, 
${substring(num,num)}, or ${substring(num,num,expression)} was: "
+                                                + function,
+                        index);
+            }
+            String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',', 
false);
+            if (tokens.length > 3) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${substring(num,num,expression)} was: " 
+ function, index);
+            }
+            String num1 = tokens[0];
+            String num2 = "0";
+            if (tokens.length > 1) {
+                num2 = tokens[1];
+            }
+            String exp = "${body}";
+            if (tokens.length == 3) {
+                exp = tokens[2];
+            }
+            return SimpleExpressionBuilder.substringExpression(exp, num1, 
num2);
+        }
+
+        remainder = ifStartsWithReturnRemainder("substringBefore(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${substringBefore(exp)} or 
${substringBefore(exp,exp)} was: " + function, index);
+            }
+            String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',', 
false);
+            if (tokens.length > 2) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${substringBefore(exp)} or 
${substringBefore(exp,exp)} was: " + function, index);
+            }
+            String exp1 = "${body}";
+            String before;
+            if (tokens.length == 2) {
+                exp1 = tokens[0];
+                before = tokens[1];
+            } else {
+                before = tokens[0];
+            }
+            return SimpleExpressionBuilder.substringBeforeExpression(exp1, 
before);
+        }
+
+        remainder = ifStartsWithReturnRemainder("substringAfter(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${substringAfter(exp)} or 
${substringAfter(exp,exp)} was: " + function, index);
+            }
+            String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',', 
false);
+            if (tokens.length > 2) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${substringAfter(exp)} or 
${substringAfter(exp,exp)} was: " + function, index);
+            }
+            String exp1 = "${body}";
+            String after;
+            if (tokens.length == 2) {
+                exp1 = tokens[0];
+                after = tokens[1];
+            } else {
+                after = tokens[0];
+            }
+            return SimpleExpressionBuilder.substringAfterExpression(exp1, 
after);
+        }
+
+        remainder = ifStartsWithReturnRemainder("substringBetween(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${substringBetween(after,before)} or 
${substringAfter(exp,after,before)} was: "
+                                                + function,
+                        index);
+            }
+            String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',', 
false);
+            if (tokens.length < 2 || tokens.length > 3) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${substringBetween(after,before)} or 
${substringAfter(exp,after,before)} was: "
+                                                + function,
+                        index);
+            }
+            String exp1 = "${body}";
+            String after;
+            String before;
+            if (tokens.length == 3) {
+                exp1 = tokens[0];
+                after = tokens[1];
+                before = tokens[2];
+            } else {
+                after = tokens[0];
+                before = tokens[1];
+            }
+            return SimpleExpressionBuilder.substringBetweenExpression(exp1, 
after, before);
+        }
+
+        remainder = ifStartsWithReturnRemainder("contains(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${contains(text)} or 
${contains(exp,text)} was: " + function, index);
+            }
+            String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',', 
false);
+            if (tokens.length < 1 || tokens.length > 2) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${contains(text)} or 
${contains(exp,text)} was: " + function, index);
+            }
+            String exp = "${body}";
+            String pattern;
+            if (tokens.length == 1) {
+                pattern = tokens[0];
+            } else {
+                exp = tokens[0];
+                pattern = tokens[1];
+            }
+            return SimpleExpressionBuilder.containsExpression(exp, pattern);
+        }
+
+        remainder = ifStartsWithReturnRemainder("trim(", function);
+        if (remainder != null) {
+            String exp = null;
+            String value = StringHelper.beforeLast(remainder, ")");
+            if (ObjectHelper.isNotEmpty(value)) {
+                exp = StringHelper.removeQuotes(value);
+            }
+            return SimpleExpressionBuilder.trimExpression(exp);
+        }
+
+        remainder = ifStartsWithReturnRemainder("val(", function);
+        if (remainder != null) {
+            String value = StringHelper.beforeLast(remainder, ")");
+            if (value == null || ObjectHelper.isEmpty(value)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${val(exp)} was: " + function, index);
+            }
+            return ExpressionBuilder.simpleExpression(value);
+        }
+
+        remainder = ifStartsWithReturnRemainder("capitalize(", function);
+        if (remainder != null) {
+            String exp = null;
+            String value = StringHelper.beforeLast(remainder, ")");
+            if (ObjectHelper.isNotEmpty(value)) {
+                exp = StringHelper.removeQuotes(value);
+            }
+            return SimpleExpressionBuilder.capitalizeExpression(exp);
+        }
+
+        remainder = ifStartsWithReturnRemainder("pad(", function);
+        if (remainder != null) {
+            String exp;
+            String len;
+            String separator = null;
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${pad(len)} or ${pad(exp,len)} or 
${pad(exp,len,separator)} was: " + function,
+                        index);
+            }
+            String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',', 
true, true);
+            if (tokens.length < 2 || tokens.length > 3) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${pad(exp,len)} or 
${pad(exp,len,separator)} was: " + function, index);
+            }
+            exp = StringHelper.removeQuotes(tokens[0]);
+            len = StringHelper.removeQuotes(tokens[1]);
+            if (tokens.length == 3) {
+                separator = StringHelper.removeQuotes(tokens[2]);
+            }
+            return SimpleExpressionBuilder.padExpression(exp, len, separator);
+        }
+
+        remainder = ifStartsWithReturnRemainder("concat(", function);
+        if (remainder != null) {
+            String separator = null;
+            String exp1 = "${body}";
+            String exp2;
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${concat(exp)} or ${concat(exp,exp)} or 
${concat(exp,exp,separator)} was: "
+                                                + function,
+                        index);
+            }
+            if (values.contains(",")) {
+                String[] tokens = StringQuoteHelper.splitSafeQuote(values, 
',', true, true);
+                if (tokens.length > 3) {
+                    throw new SimpleParserException(
+                            "Valid syntax: ${concat(exp)} or 
${concat(exp,exp)} or ${concat(exp,exp,separator)} was: "
+                                                    + function,
+                            index);
+                }
+                exp1 = StringHelper.removeQuotes(tokens[0]);
+                exp2 = StringHelper.removeQuotes(tokens[1]);
+                if (tokens.length == 3) {
+                    separator = StringHelper.removeQuotes(tokens[2]);
+                }
+            } else {
+                exp2 = StringHelper.removeQuotes(values.trim());
+            }
+            return SimpleExpressionBuilder.concatExpression(exp1, exp2, 
separator);
+        }
+
+        remainder = ifStartsWithReturnRemainder("quote(", function);
+        if (remainder != null) {
+            String exp = null;
+            String value = StringHelper.beforeLast(remainder, ")");
+            if (ObjectHelper.isNotEmpty(value)) {
+                exp = StringHelper.removeQuotes(value);
+            }
+            return SimpleExpressionBuilder.quoteExpression(exp);
+        }
+
+        remainder = ifStartsWithReturnRemainder("safeQuote(", function);
+        if (remainder != null) {
+            String exp = null;
+            String value = StringHelper.beforeLast(remainder, ")");
+            if (ObjectHelper.isNotEmpty(value)) {
+                exp = StringHelper.removeQuotes(value);
+            }
+            return SimpleExpressionBuilder.safeQuoteExpression(exp);
+        }
+
+        remainder = ifStartsWithReturnRemainder("unquote(", function);
+        if (remainder != null) {
+            String exp = null;
+            String value = StringHelper.beforeLast(remainder, ")");
+            if (ObjectHelper.isNotEmpty(value)) {
+                exp = StringHelper.removeQuotes(value);
+            }
+            return SimpleExpressionBuilder.unquoteExpression(exp);
+        }
+
+        remainder = ifStartsWithReturnRemainder("uppercase(", function);
+        if (remainder != null) {
+            String exp = null;
+            String value = StringHelper.beforeLast(remainder, ")");
+            if (ObjectHelper.isNotEmpty(value)) {
+                exp = StringHelper.removeQuotes(value);
+            }
+            return SimpleExpressionBuilder.uppercaseExpression(exp);
+        }
+
+        remainder = ifStartsWithReturnRemainder("lowercase(", function);
+        if (remainder != null) {
+            String exp = null;
+            String value = StringHelper.beforeLast(remainder, ")");
+            if (ObjectHelper.isNotEmpty(value)) {
+                exp = StringHelper.removeQuotes(value);
+            }
+            return SimpleExpressionBuilder.lowercaseExpression(exp);
+        }
+
+        remainder = ifStartsWithReturnRemainder("length(", function);
+        if (remainder != null) {
+            String exp = null;
+            String value = StringHelper.beforeLast(remainder, ")");
+            if (ObjectHelper.isNotEmpty(value)) {
+                exp = StringHelper.removeQuotes(value);
+            }
+            return SimpleExpressionBuilder.lengthExpression(exp);
+        }
+
+        remainder = ifStartsWithReturnRemainder("size(", function);
+        if (remainder != null) {
+            String exp = null;
+            String value = StringHelper.beforeLast(remainder, ")");
+            if (ObjectHelper.isNotEmpty(value)) {
+                exp = StringHelper.removeQuotes(value);
+            }
+            return SimpleExpressionBuilder.sizeExpression(exp);
+        }
+
+        remainder = ifStartsWithReturnRemainder("normalizeWhitespace(", 
function);
+        if (remainder != null) {
+            String exp = null;
+            String value = StringHelper.beforeLast(remainder, ")");
+            if (ObjectHelper.isNotEmpty(value)) {
+                exp = StringHelper.removeQuotes(value);
+            }
+            return SimpleExpressionBuilder.normalizeWhitespaceExpression(exp);
+        }
+
+        return null;
+    }
+
+    @Override
+    public String createCode(CamelContext camelContext, String function, int 
index) {
+        String remainder;
+
+        remainder = ifStartsWithReturnRemainder("substring(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${substring(num)}, 
${substring(num,num)} was: " + function, index);
+            }
+            String[] tokens = codeSplitSafe(values, ',', true, true);
+            if (tokens.length > 2) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${substring(num,num)} was: " + 
function, index);
+            }
+            String num1 = tokens[0].trim();
+            String num2 = tokens.length > 1 ? tokens[1].trim() : "0";
+            return "substring(exchange, " + num1 + ", " + num2 + ")";
+        }
+
+        remainder = ifStartsWithReturnRemainder("substringBefore(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${substringBefore(before)}, 
${substringBefore(exp,before)} was: " + function,
+                        index);
+            }
+            String[] tokens = codeSplitSafe(values, ',', true, true);
+            if (tokens.length > 2) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${substringBefore(before)}, 
${substringBefore(exp,before)} was: " + function,
+                        index);
+            }
+            for (int i = 0; i < tokens.length; i++) {
+                tokens[i] = squoteToDouble(tokens[i]);
+            }
+            String body = tokens.length > 1 ? tokens[0] : "body";
+            String before = tokens.length > 1 ? tokens[1] : tokens[0];
+            return "Object value = " + body + ";\n        Object before = " + 
before
+                   + ";\n        return substringBefore(exchange, value, 
before);";
+        }
+
+        remainder = ifStartsWithReturnRemainder("substringAfter(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${substringAfter(before)}, 
${substringAfter(exp,before)} was: " + function,
+                        index);
+            }
+            String[] tokens = codeSplitSafe(values, ',', true, true);
+            if (tokens.length > 2) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${substringAfter(before)}, 
${substringAfter(exp,before)} was: " + function,
+                        index);
+            }
+            for (int i = 0; i < tokens.length; i++) {
+                tokens[i] = squoteToDouble(tokens[i]);
+            }
+            String body = tokens.length > 1 ? tokens[0] : "body";
+            String after = tokens.length > 1 ? tokens[1] : tokens[0];
+            return "Object value = " + body + ";\n        Object after = " + 
after
+                   + ";\n        return substringAfter(exchange, value, 
after);";
+        }
+
+        remainder = ifStartsWithReturnRemainder("substringBetween(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${substringBetween(after,before)}, 
${substringBetween(exp,after,before)} was: "
+                                                + function,
+                        index);
+            }
+            String[] tokens = codeSplitSafe(values, ',', true, true);
+            if (tokens.length < 2 || tokens.length > 3) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${substringBetween(after,before)}, 
${substringBetween(exp,after,before)} was: "
+                                                + function,
+                        index);
+            }
+            for (int i = 0; i < tokens.length; i++) {
+                tokens[i] = squoteToDouble(tokens[i]);
+            }
+            String body = tokens.length == 3 ? tokens[0] : "body";
+            String after = tokens.length == 3 ? tokens[1] : tokens[0];
+            String before = tokens.length == 3 ? tokens[2] : tokens[1];
+            return "Object value = " + body + ";\n        Object after = " + 
after
+                   + ";\n        Object before = " + before
+                   + ";\n        return substringBetween(exchange, value, 
after, before);";
+        }
+
+        remainder = ifStartsWithReturnRemainder("contains(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${contains(text)} or 
${contains(exp,text)} was: " + function, index);
+            }
+            String[] tokens = codeSplitSafe(values, ',', true, true);
+            if (tokens.length < 1 || tokens.length > 2) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${contains(text)} or 
${contains(exp,text)} was: " + function, index);
+            }
+            for (int i = 0; i < tokens.length; i++) {
+                tokens[i] = squoteToDouble(tokens[i]);
+            }
+            String exp = tokens.length == 1 ? "body" : tokens[0];
+            String pattern = tokens.length == 1 ? tokens[0] : tokens[1];
+            pattern = StringHelper.removeLeadingAndEndingQuotes(pattern);
+            pattern = StringQuoteHelper.doubleQuote(pattern);
+            return "Object value = " + exp + ";\n        return 
containsIgnoreCase(exchange, value, " + pattern + ");";
+        }
+
+        remainder = ifStartsWithReturnRemainder("replace(", function);
+        if (remainder != null) {
+            String values = StringHelper.before(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${replace(from,to)} was: " + function, 
index);
+            }
+            String[] tokens = codeSplitSafe(values, ',', true, false);
+            if (tokens.length > 2) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${replace(from,to)} was: " + function, 
index);
+            }
+            String from = StringHelper.xmlDecode(tokens[0]);
+            String to = StringHelper.xmlDecode(tokens[1]);
+            if ("&empty;".equals(to)) {
+                to = "";
+            }
+            if ("\"".equals(from)) {
+                from = "\\\"";
+            }
+            if ("\"".equals(to)) {
+                to = "\\\"";
+            }
+            from = StringQuoteHelper.doubleQuote(from);
+            to = StringQuoteHelper.doubleQuote(to);
+            return "replace(exchange, " + from + ", " + to + ")";
+        }
+
+        remainder = ifStartsWithReturnRemainder("trim(", function);
+        if (remainder != null) {
+            return codeSimpleUnary("trim", remainder, function, index, "null");
+        }
+
+        remainder = ifStartsWithReturnRemainder("val(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${val(exp)} was: " + function, index);
+            }
+            String s = StringHelper.removeLeadingAndEndingQuotes(values);
+            s = StringQuoteHelper.doubleQuote(s);
+            return "Object o = " + s + ";\n        return o;";
+        }
+
+        remainder = ifStartsWithReturnRemainder("capitalize(", function);
+        if (remainder != null) {
+            return codeSimpleUnary("capitalize", remainder, function, index, 
"null");
+        }
+
+        remainder = ifStartsWithReturnRemainder("pad(", function);
+        if (remainder != null) {
+            String separator = null;
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${pad(len)} or ${pad(exp,len)} or 
${pad(exp,len,separator)} was: " + function,
+                        index);
+            }
+            String[] tokens = codeSplitSafe(values, ',', true, true);
+            if (tokens.length < 2 || tokens.length > 3) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${pad(exp,len)} or 
${pad(exp,len,separator)} was: " + function, index);
+            }
+            for (int i = 0; i < tokens.length; i++) {
+                tokens[i] = squoteToDouble(tokens[i]);
+            }
+            if (tokens.length == 3) {
+                separator = tokens[2];
+            }
+            separator = StringHelper.removeLeadingAndEndingQuotes(separator);
+            separator = separator != null ? 
StringQuoteHelper.doubleQuote(separator) : "null";
+            return "Object value = " + tokens[0] + ";\n        " + "Object 
width = " + tokens[1]
+                   + ";\n        String separator = " + separator
+                   + ";\n        return pad(exchange, value, width, 
separator);";
+        }
+
+        remainder = ifStartsWithReturnRemainder("concat(", function);
+        if (remainder != null) {
+            String separator = "null";
+            String exp1 = "body";
+            String exp2;
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${concat(exp)} or ${concat(exp,exp)} or 
${concat(exp,exp,separator)} was: "
+                                                + function,
+                        index);
+            }
+            if (values.contains(",")) {
+                String[] tokens = codeSplitSafe(values, ',', true, true);
+                if (tokens.length > 3) {
+                    throw new SimpleParserException(
+                            "Valid syntax: ${concat(exp)} or 
${concat(exp,exp)} or ${concat(exp,exp,separator)} was: "
+                                                    + function,
+                            index);
+                }
+                for (int i = 0; i < tokens.length; i++) {
+                    tokens[i] = squoteToDouble(tokens[i]);
+                }
+                if (tokens.length == 1) {
+                    exp2 = tokens[0];
+                } else {
+                    exp1 = tokens[0];
+                    exp2 = tokens[1];
+                }
+                if (tokens.length == 3) {
+                    separator = tokens[2];
+                }
+            } else {
+                String s = values.trim();
+                s = StringHelper.removeLeadingAndEndingQuotes(s);
+                s = StringQuoteHelper.doubleQuote(s);
+                exp2 = s;
+            }
+            return "Object right = " + exp2 + ";\n        Object left = " + 
exp1 + ";\n        " + "Object separator = "
+                   + separator + ";\n        return concat(exchange, left, 
right, separator);";
+        }
+
+        remainder = ifStartsWithReturnRemainder("quote(", function);
+        if (remainder != null) {
+            return codeSimpleUnary("quote", remainder, function, index, 
"null");
+        }
+
+        remainder = ifStartsWithReturnRemainder("safeQuote(", function);
+        if (remainder != null) {
+            return codeSimpleUnary("safeQuote", remainder, function, index, 
"body");
+        }
+
+        remainder = ifStartsWithReturnRemainder("unquote(", function);
+        if (remainder != null) {
+            String exp = null;
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (ObjectHelper.isNotEmpty(values)) {
+                String[] tokens = codeSplitSafe(values, ',', true, true);
+                if (tokens.length != 1) {
+                    throw new SimpleParserException(
+                            "Valid syntax: ${unquote(exp)} was: " + function, 
index);
+                }
+                String s = tokens[0];
+                if (StringHelper.isSingleQuoted(s)) {
+                    s = StringHelper.removeLeadingAndEndingQuotes(s);
+                    s = s.replace("\"", "\\\"");
+                    s = StringQuoteHelper.doubleQuote(s);
+                }
+                exp = s;
+            }
+            if (ObjectHelper.isEmpty(exp)) {
+                exp = "null";
+            }
+            return "Object o = " + exp + ";\n        return unquote(exchange, 
o);";
+        }
+
+        remainder = ifStartsWithReturnRemainder("uppercase(", function);
+        if (remainder != null) {
+            return codeSimpleUnary("uppercase", remainder, function, index, 
"null");
+        }
+
+        remainder = ifStartsWithReturnRemainder("lowercase(", function);
+        if (remainder != null) {
+            return codeSimpleUnary("lowercase", remainder, function, index, 
"null");
+        }
+
+        remainder = ifStartsWithReturnRemainder("length(", function);
+        if (remainder != null) {
+            return codeSimpleUnary("length", remainder, function, index, 
"body");
+        }
+
+        remainder = ifStartsWithReturnRemainder("size(", function);
+        if (remainder != null) {
+            return codeSimpleUnary("size", remainder, function, index, "body");
+        }
+
+        remainder = ifStartsWithReturnRemainder("normalizeWhitespace(", 
function);
+        if (remainder != null) {
+            return codeSimpleUnary("normalizeWhitespace", remainder, function, 
index, "null");
+        }
+
+        return null;
+    }
+
+    private static String codeSimpleUnary(String name, String remainder, 
String function, int index, String defaultExp) {
+        String exp = null;
+        String values = StringHelper.beforeLast(remainder, ")");
+        if (ObjectHelper.isNotEmpty(values)) {
+            String[] tokens = codeSplitSafe(values, ',', true, true);
+            if (tokens.length != 1) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${" + name + "(exp)} was: " + function, 
index);
+            }
+            String s = tokens[0];
+            if (StringHelper.isSingleQuoted(s)) {
+                s = StringHelper.removeLeadingAndEndingQuotes(s);
+                s = StringQuoteHelper.doubleQuote(s);
+            }
+            exp = s;
+        }
+        if (ObjectHelper.isEmpty(exp)) {
+            exp = defaultExp;
+        }
+        return "Object o = " + exp + ";\n        return " + name + "(exchange, 
o);";
+    }
+
+    private static String squoteToDouble(String s) {
+        if (StringHelper.isSingleQuoted(s)) {
+            s = StringHelper.removeLeadingAndEndingQuotes(s);
+            s = StringQuoteHelper.doubleQuote(s);
+        }
+        return s;
+    }
+}
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/MathFunctionFactoryTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/MathFunctionFactoryTest.java
new file mode 100644
index 000000000000..b5a868368724
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/MathFunctionFactoryTest.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.language.simple.functions;
+
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class MathFunctionFactoryTest extends 
AbstractSimpleFunctionFactoryTestSupport {
+
+    @Override
+    protected SimpleLanguageFunctionFactory createFactory() {
+        return new MathFunctionFactory();
+    }
+
+    @Test
+    public void testAbs() {
+        exchange.getIn().setBody(-5);
+        assertEquals(5, evaluate("abs(${body})", Integer.class));
+    }
+
+    @Test
+    public void testAbsLiteral() {
+        assertEquals(7.0, evaluate("abs(-7)", Double.class));
+    }
+
+    @Test
+    public void testFloor() {
+        exchange.getIn().setBody(3.7);
+        assertEquals(3L, evaluate("floor(${body})", Long.class));
+    }
+
+    @Test
+    public void testCeil() {
+        exchange.getIn().setBody(3.2);
+        assertEquals(4L, evaluate("ceil(${body})", Long.class));
+    }
+
+    @Test
+    public void testSum() {
+        assertEquals(6.0, evaluate("sum(1, 2, 3)", Double.class));
+    }
+
+    @Test
+    public void testSumWithBody() {
+        exchange.getIn().setBody(10);
+        assertEquals(16.0, evaluate("sum(${body}, 3, 3)", Double.class));
+    }
+
+    @Test
+    public void testMax() {
+        assertEquals(3.0, evaluate("max(1, 2, 3)", Double.class));
+    }
+
+    @Test
+    public void testMin() {
+        assertEquals(1.0, evaluate("min(1, 2, 3)", Double.class));
+    }
+
+    @Test
+    public void testAverage() {
+        assertEquals(2.0, evaluate("average(1, 2, 3)", Double.class));
+    }
+
+    @Test
+    public void testCreateCodeAbs() {
+        assertEquals("Object o = null;\n        return abs(exchange, o);", 
createCode("abs()"));
+        assertEquals("Object o = 5;\n        return abs(exchange, o);", 
createCode("abs(5)"));
+    }
+
+    @Test
+    public void testCreateCodeFloor() {
+        assertEquals("Object o = null;\n        return floor(exchange, o);", 
createCode("floor()"));
+        assertEquals("Object o = 3.7;\n        return floor(exchange, o);", 
createCode("floor(3.7)"));
+    }
+
+    @Test
+    public void testCreateCodeCeil() {
+        assertEquals("Object o = null;\n        return ceil(exchange, o);", 
createCode("ceil()"));
+    }
+
+    @Test
+    public void testCreateCodeSum() {
+        assertEquals("sum(exchange, 1, 2, 3)", createCode("sum(1, 2, 3)"));
+    }
+
+    @Test
+    public void testCreateCodeMax() {
+        assertEquals("max(exchange, 1, 2)", createCode("max(1, 2)"));
+    }
+
+    @Test
+    public void testCreateCodeMin() {
+        assertEquals("min(exchange, 1, 2)", createCode("min(1, 2)"));
+    }
+
+    @Test
+    public void testCreateCodeAverage() {
+        assertEquals("average(exchange, 1, 2, 3)", createCode("average(1, 2, 
3)"));
+    }
+
+    @Test
+    public void testUnknownFunctionReturnsNull() {
+        assertNull(createFactory().createFunction(context, "trim()", 0));
+        assertNull(createFactory().createCode(context, "trim()", 0));
+    }
+}
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/StringFunctionFactoryTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/StringFunctionFactoryTest.java
new file mode 100644
index 000000000000..f9d76206bccc
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/StringFunctionFactoryTest.java
@@ -0,0 +1,319 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.language.simple.functions;
+
+import java.util.List;
+
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class StringFunctionFactoryTest extends 
AbstractSimpleFunctionFactoryTestSupport {
+
+    @Override
+    protected SimpleLanguageFunctionFactory createFactory() {
+        return new StringFunctionFactory();
+    }
+
+    // --- replace ---
+
+    @Test
+    public void testReplace() {
+        exchange.getIn().setBody("Hello World");
+        assertEquals("Hello Camel", evaluate("replace(World,Camel)", 
String.class));
+    }
+
+    @Test
+    public void testReplaceWithExpression() {
+        exchange.getIn().setHeader("msg", "foo bar");
+        assertEquals("foo-bar", evaluate("replace( ,-,${header.msg})", 
String.class));
+    }
+
+    @Test
+    public void testCreateCodeReplace() {
+        assertEquals("replace(exchange, \"a\", \"b\")", 
createCode("replace(a,b)"));
+    }
+
+    @Test
+    public void testCreateCodeReplaceEmpty() {
+        assertEquals("replace(exchange, \"a\", \"\")", 
createCode("replace(a,&empty;)"));
+    }
+
+    // --- substring ---
+
+    @Test
+    public void testSubstringRange1() {
+        exchange.getIn().setBody("Hello World");
+        assertEquals("World", evaluate("substring(6)", String.class));
+    }
+
+    @Test
+    public void testSubstringRange2() {
+        exchange.getIn().setBody("Hello World");
+        assertEquals("Hello", evaluate("substring(0,6)", String.class));
+    }
+
+    @Test
+    public void testSubstringRange3() {
+        exchange.getIn().setBody("Hello World");
+        assertEquals("", evaluate("substring(6,5)", String.class));
+    }
+
+    @Test
+    public void testSubstringRange4() {
+        assertEquals("World", evaluate("substring(6,0,'Hello World')", 
String.class));
+    }
+
+    @Test
+    public void testCreateCodeSubstring() {
+        assertEquals("substring(exchange, 2, 0)", createCode("substring(2)"));
+        assertEquals("substring(exchange, 1, 5)", createCode("substring(1, 
5)"));
+    }
+
+    // --- substringBefore / substringAfter / substringBetween ---
+
+    @Test
+    public void testSubstringBefore() {
+        exchange.getIn().setBody("Hello World");
+        assertEquals("Hello ", evaluate("substringBefore(World)", 
String.class));
+    }
+
+    @Test
+    public void testSubstringAfter() {
+        exchange.getIn().setBody("Hello World");
+        assertEquals(" World", evaluate("substringAfter(Hello)", 
String.class));
+    }
+
+    @Test
+    public void testSubstringBetween() {
+        exchange.getIn().setBody("[Hello World]");
+        assertEquals("Hello World", evaluate("substringBetween([,])", 
String.class));
+    }
+
+    @Test
+    public void testCreateCodeSubstringBefore() {
+        assertEquals(
+                "Object value = body;\n        Object before = \" \";\n        
return substringBefore(exchange, value, before);",
+                createCode("substringBefore(' ')"));
+    }
+
+    @Test
+    public void testCreateCodeSubstringAfterWithExp() {
+        assertEquals(
+                "Object value = body;\n        Object after = \" \";\n        
return substringAfter(exchange, value, after);",
+                createCode("substringAfter(' ')"));
+    }
+
+    // --- contains ---
+
+    @Test
+    public void testContains() {
+        exchange.getIn().setBody("Hello World");
+        assertEquals(true, evaluate("contains(World)", Boolean.class));
+        assertEquals(false, evaluate("contains(Camel)", Boolean.class));
+    }
+
+    @Test
+    public void testContainsWithExpression() {
+        exchange.getIn().setHeader("greeting", "Hello World");
+        assertEquals(true, evaluate("contains(${header.greeting}, World)", 
Boolean.class));
+    }
+
+    @Test
+    public void testCreateCodeContains() {
+        assertEquals(
+                "Object value = body;\n        return 
containsIgnoreCase(exchange, value, \"World\");",
+                createCode("contains(World)"));
+    }
+
+    // --- trim ---
+
+    @Test
+    public void testTrim() {
+        exchange.getIn().setBody("  hello  ");
+        assertEquals("hello", evaluate("trim()", String.class));
+    }
+
+    @Test
+    public void testCreateCodeTrim() {
+        assertEquals("Object o = null;\n        return trim(exchange, o);", 
createCode("trim()"));
+        assertEquals("Object o = body;\n        return trim(exchange, o);", 
createCode("trim(body)"));
+    }
+
+    // --- val ---
+
+    @Test
+    public void testVal() {
+        exchange.getIn().setBody("hello");
+        assertEquals("hello", evaluate("val(${body})", String.class));
+    }
+
+    @Test
+    public void testCreateCodeVal() {
+        assertEquals("Object o = \"hello\";\n        return o;", 
createCode("val('hello')"));
+    }
+
+    // --- capitalize ---
+
+    @Test
+    public void testCapitalize() {
+        exchange.getIn().setBody("hello world");
+        assertEquals("Hello World", evaluate("capitalize()", String.class));
+    }
+
+    @Test
+    public void testCreateCodeCapitalize() {
+        assertEquals("Object o = null;\n        return capitalize(exchange, 
o);", createCode("capitalize()"));
+    }
+
+    // --- pad ---
+
+    @Test
+    public void testPad() {
+        exchange.getIn().setBody("hi");
+        assertEquals("hi   ", evaluate("pad(${body}, 5)", String.class));
+    }
+
+    @Test
+    public void testCreateCodePad() {
+        assertEquals(
+                "Object value = body;\n        Object width = 10;\n        
String separator = null;\n        return pad(exchange, value, width, 
separator);",
+                createCode("pad(body, 10)"));
+    }
+
+    // --- concat ---
+
+    @Test
+    public void testConcat() {
+        exchange.getIn().setBody("Hello");
+        assertEquals("Hello World", evaluate("concat(${body}, World, ' ')", 
String.class));
+    }
+
+    @Test
+    public void testCreateCodeConcat() {
+        assertEquals(
+                "Object right = \"World\";\n        Object left = body;\n      
  Object separator = null;\n        return concat(exchange, left, right, 
separator);",
+                createCode("concat('World')"));
+    }
+
+    // --- quote / safeQuote / unquote ---
+
+    @Test
+    public void testQuote() {
+        exchange.getIn().setBody("hello");
+        assertEquals("\"hello\"", evaluate("quote()", String.class));
+    }
+
+    @Test
+    public void testSafeQuote() {
+        exchange.getIn().setBody("hello");
+        assertEquals("\"hello\"", evaluate("safeQuote()", String.class));
+    }
+
+    @Test
+    public void testUnquote() {
+        exchange.getIn().setBody("'hello'");
+        assertEquals("hello", evaluate("unquote()", String.class));
+    }
+
+    @Test
+    public void testCreateCodeQuote() {
+        assertEquals("Object o = null;\n        return quote(exchange, o);", 
createCode("quote()"));
+    }
+
+    @Test
+    public void testCreateCodeSafeQuote() {
+        assertEquals("Object o = body;\n        return safeQuote(exchange, 
o);", createCode("safeQuote()"));
+    }
+
+    @Test
+    public void testCreateCodeUnquote() {
+        assertEquals("Object o = null;\n        return unquote(exchange, o);", 
createCode("unquote()"));
+    }
+
+    // --- uppercase / lowercase ---
+
+    @Test
+    public void testUppercase() {
+        exchange.getIn().setBody("hello");
+        assertEquals("HELLO", evaluate("uppercase()", String.class));
+    }
+
+    @Test
+    public void testLowercase() {
+        exchange.getIn().setBody("HELLO");
+        assertEquals("hello", evaluate("lowercase()", String.class));
+    }
+
+    @Test
+    public void testCreateCodeUppercase() {
+        assertEquals("Object o = null;\n        return uppercase(exchange, 
o);", createCode("uppercase()"));
+    }
+
+    @Test
+    public void testCreateCodeLowercase() {
+        assertEquals("Object o = null;\n        return lowercase(exchange, 
o);", createCode("lowercase()"));
+    }
+
+    // --- length / size ---
+
+    @Test
+    public void testLength() {
+        exchange.getIn().setBody("Hello");
+        assertEquals(5, evaluate("length()", Integer.class));
+    }
+
+    @Test
+    public void testSize() {
+        exchange.getIn().setBody(List.of("a", "b", "c"));
+        assertEquals(3, evaluate("size()", Integer.class));
+    }
+
+    @Test
+    public void testCreateCodeLength() {
+        assertEquals("Object o = body;\n        return length(exchange, o);", 
createCode("length()"));
+    }
+
+    @Test
+    public void testCreateCodeSize() {
+        assertEquals("Object o = body;\n        return size(exchange, o);", 
createCode("size()"));
+    }
+
+    // --- normalizeWhitespace ---
+
+    @Test
+    public void testNormalizeWhitespace() {
+        exchange.getIn().setBody("  hello   world  ");
+        assertEquals("hello world", evaluate("normalizeWhitespace()", 
String.class));
+    }
+
+    @Test
+    public void testCreateCodeNormalizeWhitespace() {
+        assertEquals("Object o = null;\n        return 
normalizeWhitespace(exchange, o);",
+                createCode("normalizeWhitespace()"));
+    }
+
+    // --- unknown function ---
+
+    @Test
+    public void testUnknownFunctionReturnsNull() {
+        assertNull(createFactory().createFunction(context, "abs()", 0));
+        assertNull(createFactory().createCode(context, "abs()", 0));
+    }
+}


Reply via email to