Skip to main content

Strings

The Strings category covers functions for building, reshaping, searching, and measuring text, including file names and logical paths. You can call each one in prefix form fn(s, …) or in postfix/UFCS form s fn(…).

Some text operations you might expect here live in Core instead, because they generalize beyond strings: upper, lower, trim, replace (literal), contains, startsWith, endsWith, indexOf, splitBy, and joinBy.

File Names and Paths

These functions calculate names and paths from text without reading files, checking whether a path exists, or moving its contents. Use them to extract a name from an incoming path or calculate a destination for a later file operation.

fileName, fileStem, fileExtension, directoryName, and pathSegment accept a String path or null and return a String or null. A null path returns null. They use / as the path separator. In pathSegment, leading and repeated slashes create empty segments, while trailing empty segments are omitted.

FunctionSignatureDescriptionExample
fileName(:string?)Last name in the path, including its extension. Trailing slashes are ignored.fileName("inbound/report.tar.gz") → "report.tar.gz"
fileStem(:string?)Last name with only its final extension removed.fileStem("inbound/report.tar.gz") → "report.tar"
fileExtension(:string?)Final extension, including the leading dot. Returns "" when there is no extension.fileExtension("inbound/report.tar.gz") → ".gz"
directoryName(:string?)Parent path. Returns "." when the name has no parent.directoryName("inbound/report.csv") → "inbound"
pathSegment(:string?, :number)Segment at a zero-based integer index. Negative indices count from the end; an index outside the path returns null.pathSegment("partner/inbound/report.csv", -1) → "report.csv"
normalizePath(:string)Returns a String with backslashes converted to /, empty segments and . and .. components removed, and NUL characters removed. The result has no leading or trailing slash.normalizePath("reports/../out") → "reports/out"
resolvePath(:string, :string)Returns a String formed by normalizing the base, joining the second path, and resolving . and .. in the joined path. The result has no leading slash.resolvePath("reports/2026", "../out/report.csv") → "reports/out/report.csv"

An extension keeps its original case. A leading dot alone does not make an extension: fileExtension(".env") returns "", while fileStem(".env.local") returns ".env". For an empty path, the name, stem, and extension are "", and the directory name is ".".

Choose normalizePath to remove unwanted path components, and resolvePath when parent components must change the destination. Normalization removes .. without removing the preceding segment; resolution applies it:

normalizePath("reports/../out")       // → "reports/out"
resolvePath("", "reports/../out")     // → "out"
normalizePath("reports\\2026\\out")   // → "reports/2026/out"

In resolvePath, a leading slash in the second path does not discard the base: resolvePath("reports", "/out") returns "reports/out". Parent components cannot move above the logical root; resolvePath("", "../../out") returns "out".

Non-null path arguments must be Strings; other types raise an error. normalizePath and resolvePath reject null. pathSegment requires an integer index even when the path is null; a fractional index such as 1.5 raises an error. A NUL character in the second argument to resolvePath raises an invalid-path error.

Casing and Inflection

These apply natural-language transforms.

FunctionSignatureDescriptionExample
camelize(:string)Splits on non-alphanumerics; lowercases the first word, TitleCases the rest, joins them.camelize("hello_world") → "helloWorld"
capitalize(:string)First character upper, the rest lower.capitalize("hELLO") → "Hello"
dasherize(:string)Normalizes spaces/underscores/dashes and returns a kebab-cased string.dasherize("Hello World") → "hello-world"
underscore(:string)Snake-cases the input (dashes and spaces become underscores).underscore("helloWorld") → "hello_world"
ordinalize(:number)The ordinal string for a number.ordinalize(3) → "3rd"
pluralize(:string, :number?)Pluralizes a word; with a count, pluralizes only when the count isn't 1.pluralize("person") → "people"; pluralize("apple", 1) → "apple"
singularize(:string)Singularizes a word.singularize("people") → "person"
transliterate(:string?)Returns a String with supported characters converted to ASCII equivalents. Characters without a known equivalent become ?. A null input returns null; other non-String inputs raise an error.transliterate("Résumé Q3") → "Resume Q3"

Padding and Wrapping

FunctionSignatureDescriptionExample
leftPad(:string, :number, :string?)Pads on the left to a target length (pad string defaults to a space).leftPad("7", 3, "0") → "007"
rightPad(:string, :number, :string?)Pads on the right to a target length.rightPad("7", 3, ".") → "7.."
repeat(:string, :number)Repeats the string N times.repeat("ab", 3) → "ababab"
wrapWith(:string, :string)Wraps the value with the given string on both sides, unconditionally.wrapWith("x", "*") → "*x*"
wrapIfMissing(:string, :string)Adds the wrapper to each end only where it isn't already present.wrapIfMissing("*x", "*") → "*x*"
unwrap(:string, :string)Removes the wrapper from both ends when present on both.unwrap("*x*", "*") → "x"
appendIfMissing(:string, :string, :any?)Appends the suffix unless it's already there (3rd arg = ignore case).appendIfMissing("file", ".txt") → "file.txt"
prependIfMissing(:string, :string, :any?)Prepends the prefix unless it's already there.prependIfMissing("path", "/") → "/path"

Search and Tests

FunctionSignatureDescriptionExample
countMatches(:string, :string)Counts regex matches of the pattern in the string.countMatches("a-b-c", "-") → 2
isAlpha(:string)True if non-empty and all letters.isAlpha("abc") → true
isAlphanumeric(:string)True if non-empty and all letters/digits.isAlphanumeric("ab12") → true
isLowerCase(:string)True if non-empty and all lowercase.isLowerCase("abc") → true
isUpperCase(:string)True if non-empty and all uppercase.isUpperCase("ABC") → true
isWhitespace(:string)True if empty or all whitespace.isWhitespace(" ") → true
isNumeric(:any)True only if the value is a Number (not a numeric string).isNumeric(42) → true; isNumeric("42") → false

Substrings and Truncation

FunctionSignatureDescriptionExample
substring(:string, :number, :number?)Slice from a start index; with a length, that many chars, else to the end.substring("hello", 1, 3) → "ell"
substringBefore(:string, :string)Text before the first occurrence of a separator.substringBefore("a=b=c", "=") → "a"
substringAfter(:string, :string)Text after the first occurrence.substringAfter("a=b=c", "=") → "b=c"
substringBeforeLast(:string, :string)Text before the last occurrence.substringBeforeLast("a=b=c", "=") → "a=b"
substringAfterLast(:string, :string)Text after the last occurrence.substringAfterLast("a=b=c", "=") → "c"
substringEvery(:string, :number)Chunks the string into fixed-size pieces (an array).substringEvery("abcdef", 2) → ["ab","cd","ef"]
first(:string, :number?)The first N characters (default 1).first("hello", 2) → "he"
last(:string, :number?)The last N characters (default 1).last("hello", 2) → "lo"
withMaxSize(:string, :number)Caps length to N, keeping the last N characters if longer.withMaxSize("hello", 3) → "llo"
remove(:string, :string)Removes every regex match of the pattern.remove("a1b2", "[0-9]") → "ab"
replaceAll(:string, :string, :string)Literal (non-regex) replacement of all occurrences.replaceAll("a.b.c", ".", "-") → "a-b-c"

Regular Expressions

replaceRegex replaces every match of a regular expression in one pass over the original text. Inserted replacement text is not matched again during that call. Use replaceAll above for literal replacement, or regexEscape when text containing punctuation must be matched literally within a regular expression.

FunctionSignatureDescriptionExample
regexEscape(:string)Returns a String with regular-expression punctuation escaped for literal matching.regexEscape("a.b[0]") → "a\\.b\\[0\\]"
replaceRegex(:string, :string, :any)Returns a String with matches replaced by a String, an Object lookup, or a function receiving each complete match.replaceRegex("report Q3.csv", "\\s+", "_") → "report_Q3.csv"

The text and pattern must be Strings, and the pattern contains regular-expression syntax rather than a Regex literal. regexEscape rejects null; replaceRegex rejects null text, a null pattern, and a null replacement. An invalid pattern raises an Invalid regular expression error. A replacement of any type other than String, Object, or function also raises an error.

Write a regular-expression backslash twice in a TransformScript string: "\\s+" supplies the pattern \s+. regexEscape supplies those escapes for literal input, so the dot and brackets below are matched as characters:

replaceRegex("a.b[0] axb0", regexEscape("a.b[0]"), "matched")
// → "matched axb0"

A String replacement can reference captured groups with \1, \2, and so on. Those backslashes also need to be doubled in the TransformScript string:

replaceRegex("report-2026.csv", "report-(\\d+)", "summary-\\1")
// → "summary-2026.csv"

An Object replacement looks up the complete matched text, not the pattern or a captured group. Use String values for the replacement text. A missing key or a null value replaces the match with "":

replaceRegex("name/year", "name|year", { name: "year", year: "name" })
// → "year/name"

replaceRegex("a.b", regexEscape("a.b"), { "a.b": "matched" })
// → "matched"

A function receives each complete match and must return a String. Returning a Number, Object, or null raises an error:

replaceRegex("one/2/two", "[a-z]+", (matched) -> upper(matched))
// → "ONE/2/TWO"

Lines, Words, and Runs

FunctionSignatureDescriptionExample
lines(:string)Splits on \r\n, \r, or \n into an array of lines.lines("a\nb") → ["a","b"]
words(:string)Extracts alphanumeric (plus apostrophe) words.words("it's a test") → ["it's","a","test"]
collapse(:string)Groups runs of identical consecutive characters.collapse("aabbb") → ["aa","bbb"]

Character-Level and Code Points

FunctionSignatureDescriptionExample
charCode(:string)Code point of the first character.charCode("A") → 65
charCodeAt(:string, :number)Code point at a given index.charCodeAt("ABC", 1) → 66
fromCharCode(:number)Character for a Unicode code point.fromCharCode(65) → "A"
mapString(:string, :lambda)Maps each character (char, index) to a string and concatenates.mapString("abc", (c) -> upper(c)) → "ABC"
everyCharacter(:string, :lambda)True if every character satisfies the predicate.everyCharacter("abc", $ isAlpha()) → true
someCharacter(:string, :lambda)True if any character satisfies the predicate.someCharacter("a1c", $ isNumeric()) → false
countCharactersBy(:string, :lambda)Counts characters satisfying the predicate.countCharactersBy("a1b2", (c) -> c isNumeric()) → 0
substringBy(:string, :lambda)Splits into segments, treating chars where the lambda is truthy as delimiters.substringBy("a,b;c", (c) -> c == "," or c == ";") → ["a","b","c"]

Distance Metrics

FunctionSignatureDescriptionExample
hammingDistance(:string, :string)Count of differing positions; requires equal-length inputs (raises otherwise).hammingDistance("karolin", "kathrin") → 3
levenshteinDistance(:string, :string)Minimum single-character edits to turn one string into the other.levenshteinDistance("kitten", "sitting") → 3

Reversal

FunctionSignatureDescriptionExample
reverse(:any)Reverses a String, Array, or Object (entry order).reverse("abc") → "cba"