Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

String Operators

String manipulation and searching operations.

Feature flags (Rust crate). cat, substr, and in are baseline. length, starts_with, ends_with, upper, lower, trim, and split require the ext-string feature. Every language binding enables all operator features, so this only affects the Rust crate. See the feature table.

Argument counts: cat takes any number of arguments; substr one to three; in, starts_with, ends_with and split two; length, upper, lower and trim one. With too few arguments, substr returns "", in returns false, and the others raise Invalid Arguments. Extra arguments are ignored, except by length, which raises Invalid Arguments.

substr, starts_with, ends_with, upper, lower, trim and split convert a non-string argument to its string form first: 12 becomes "12" and null becomes "".

cat

Concatenate strings together.

Syntax:

{ "cat": [a, b, ...] }

Arguments:

  • a, b, … - Values to concatenate (variadic)

Returns: Concatenated string. Numbers and booleans add their text, null adds nothing, and an array argument adds each of its items.

Examples:

// Simple concatenation
{ "cat": ["Hello", " ", "World"] }
// Result: "Hello World"

// With variables
{ "cat": ["Hello, ", { "var": "name" }, "!"] }
// Data: { "name": "Alice" }
// Result: "Hello, Alice!"

// Non-strings are converted
{ "cat": ["Value: ", 42] }
// Result: "Value: 42"

{ "cat": ["Is active: ", true] }
// Result: "Is active: true"

// Building paths
{ "cat": ["/users/", { "var": "userId" }, "/profile"] }
// Data: { "userId": 123 }
// Result: "/users/123/profile"

Try it:


substr

Extract a substring.

Syntax:

{ "substr": [string, start] }
{ "substr": [string, start, length] }

Arguments:

  • string - Source string
  • start - Starting index (0-based, negative counts from end)
  • length - Number of characters (optional, negative counts from end)

A start or length that is not an integer counts as absent: { "substr": ["abcdef", 1.5] } is "abcdef".

Returns: Extracted substring.

Examples:

// From start index
{ "substr": ["Hello World", 0, 5] }
// Result: "Hello"

// From middle
{ "substr": ["Hello World", 6] }
// Result: "World"

// Negative start (from end)
{ "substr": ["Hello World", -5] }
// Result: "World"

// Negative length (exclude from end)
{ "substr": ["Hello World", 0, -6] }
// Result: "Hello"

// Get file extension
{ "substr": ["document.pdf", -3] }
// Result: "pdf"

// With variables
{ "substr": [{ "var": "text" }, 0, 10] }
// Data: { "text": "This is a long string" }
// Result: "This is a "

Try it:


in

Check if a value is contained in a string or array.

Syntax:

{ "in": [needle, haystack] }

Arguments:

  • needle - Value to search for
  • haystack - String or array to search in

Returns: true if found, false otherwise.

Examples:

// String contains substring
{ "in": ["World", "Hello World"] }
// Result: true

{ "in": ["xyz", "Hello World"] }
// Result: false

// Array contains element
{ "in": [2, [1, 2, 3]] }
// Result: true

{ "in": [5, [1, 2, 3]] }
// Result: false

// Check membership
{ "in": [{ "var": "role" }, ["admin", "moderator"]] }
// Data: { "role": "admin" }
// Result: true

// Check substring
{ "in": ["@", { "var": "email" }] }
// Data: { "email": "user@example.com" }
// Result: true

Try it:

Notes:

  • A string haystack requires a string needle: { "in": [2, "123"] } is false; the engine never stringifies numbers for substring search
  • Array membership uses strict deep equality (the same predicate as distinct): { "in": ["2", [1, 2, 3]] } is false, while { "in": [1, [1.0, 2]] } is true and nested arrays/objects compare structurally
  • Any other haystack (an object, null, a missing variable) yields false, as does a missing haystack argument

length

Get the length of a string or array.

Syntax:

{ "length": value }

Arguments:

  • value - String or array

Returns: Length (number of characters or elements).

Examples:

// String length
{ "length": "Hello" }
// Result: 5

// Array length (pass a value that resolves to an array)
{ "length": { "var": "nums" } }
// Data: { "nums": [1, 2, 3, 4, 5] }
// Result: 5

// Empty string
{ "length": "" }
// Result: 0

// Empty array (data-driven)
{ "length": { "var": "empty" } }
// Data: { "empty": [] }
// Result: 0

// With variables
{ "length": { "var": "items" } }
// Data: { "items": ["a", "b", "c"] }
// Result: 3

// Check minimum length
{ ">=": [{ "length": { "var": "password" } }, 8] }
// Data: { "password": "secret123" }
// Result: true

Notes:

  • length takes exactly one argument. The engine parses a literal array such as { "length": [1, 2, 3] } as a multi-argument call, which throws Invalid Arguments. Pass a single value that resolves to an array (for example { "length": { "var": "items" } }), or wrap the literal in one more array: { "length": [[1, 2, 3]] } is 3.
  • length accepts only strings and arrays: null (including a missing var), numbers, booleans, and objects throw Invalid Arguments. Guard optional fields with ??, for example { "length": { "??": [{ "var": "items" }, []] } }, which is 0 when items is absent.
  • String length counts Unicode characters, not bytes ({ "length": "héllo" } is 5).

Try it:


starts_with

Check if a string starts with a prefix.

Syntax:

{ "starts_with": [string, prefix] }

Arguments:

  • string - String to check
  • prefix - Prefix to look for

Returns: true if string starts with prefix, false otherwise.

Examples:

{ "starts_with": ["Hello World", "Hello"] }
// Result: true

{ "starts_with": ["Hello World", "World"] }
// Result: false

// Check URL scheme
{ "starts_with": [{ "var": "url" }, "https://"] }
// Data: { "url": "https://example.com" }
// Result: true

// Case sensitive
{ "starts_with": ["Hello", "hello"] }
// Result: false

Try it:


ends_with

Check if a string ends with a suffix.

Syntax:

{ "ends_with": [string, suffix] }

Arguments:

  • string - String to check
  • suffix - Suffix to look for

Returns: true if string ends with suffix, false otherwise.

Examples:

{ "ends_with": ["Hello World", "World"] }
// Result: true

{ "ends_with": ["Hello World", "Hello"] }
// Result: false

// Check file extension
{ "ends_with": [{ "var": "filename" }, ".pdf"] }
// Data: { "filename": "report.pdf" }
// Result: true

// Case sensitive
{ "ends_with": ["test.PDF", ".pdf"] }
// Result: false

Try it:


upper

Convert string to uppercase.

Syntax:

{ "upper": string }

Arguments:

  • string - String to convert

Returns: Uppercase string.

Examples:

{ "upper": "hello" }
// Result: "HELLO"

{ "upper": "Hello World" }
// Result: "HELLO WORLD"

// With variable
{ "upper": { "var": "name" } }
// Data: { "name": "alice" }
// Result: "ALICE"

// Unicode case mapping can change the length
{ "upper": "straße" }
// Result: "STRASSE"

Try it:


lower

Convert string to lowercase.

Syntax:

{ "lower": string }

Arguments:

  • string - String to convert

Returns: Lowercase string.

Examples:

{ "lower": "HELLO" }
// Result: "hello"

{ "lower": "Hello World" }
// Result: "hello world"

// Case-insensitive comparison
{ "==": [
    { "lower": { "var": "input" } },
    "yes"
]}
// Data: { "input": "YES" }
// Result: true

// Context-sensitive rules: a final Greek capital sigma becomes ς
{ "lower": "ΟΔΟΣ" }
// Result: "οδος"

Try it:

Notes:

  • upper and lower apply Unicode’s full case mappings (Rust’s str::to_uppercase / str::to_lowercase), context-sensitive rules such as the Greek final sigma included

trim

Remove leading and trailing whitespace.

Syntax:

{ "trim": string }

Arguments:

  • string - String to trim

Returns: String with whitespace removed from both ends.

Examples:

{ "trim": "  hello  " }
// Result: "hello"

{ "trim": "\n\ttext\n\t" }
// Result: "text"

// Clean user input
{ "trim": { "var": "userInput" } }
// Data: { "userInput": "  search query  " }
// Result: "search query"

Try it:


split

Split a string into an array.

Syntax:

{ "split": [string, delimiter] }

Arguments:

  • string - String to split
  • delimiter - Delimiter to split on

Returns: Array of substrings.

Examples:

// Split by space
{ "split": ["Hello World", " "] }
// Result: ["Hello", "World"]

// Split by comma
{ "split": ["a,b,c", ","] }
// Result: ["a", "b", "c"]

// Split by empty string (characters)
{ "split": ["abc", ""] }
// Result: ["a", "b", "c"]

// Parse CSV-like data
{ "split": [{ "var": "tags" }, ","] }
// Data: { "tags": "rust,json,logic" }
// Result: ["rust", "json", "logic"]

// Split an email address
{ "split": ["user@example.com", "@"] }
// Result: ["user", "example.com"]

Try it:

Notes:

  • split reads exactly two arguments. There is no limit argument: { "split": ["a,b,c,d", ",", 2] } still returns all four parts, and a single argument is Invalid Arguments
  • An empty input string gives [""]

See Also