strings
String manipulation: splitting, joining, trimming, case, search, padding.
introduce stringsStrings are immutable — every function here returns a new string.
| Function | Signature | Returns |
|---|---|---|
split | split(s, delim) | array |
join | join(arr, delim) | str |
lines | lines(s) | array |
trim | trim(s) | str |
strip | strip(s, chars) | str |
strip_left | strip_left(s, chars) | str |
strip_right | strip_right(s, chars) | str |
upper | upper(s) | str |
lower | lower(s) | str |
capitalize | capitalize(s) | str |
replace | replace(s, old, new) | str |
starts_with | starts_with(s, prefix) | bool |
ends_with | ends_with(s, suffix) | bool |
contains_str | contains_str(s, sub) | bool |
contains | contains(s, sub) | bool |
index_of | index_of(s, sub, start?) | int (-1 if absent) |
count | count(s, sub) | int |
slice | slice(s, start, end) | str |
char_at | char_at(s, i) | str |
is_empty | is_empty(s) | bool |
byte_len | byte_len(s) | int |
reverse | reverse(s) | str |
repeated | repeated(s, n) | str |
pad_left | pad_left(s, width, fill) | str |
pad_right | pad_right(s, width, fill) | str |
#Splitting and joining
#split(s, delim)
Split on a literal delimiter. Returns an array of strings.
println(strings.split("a,b,c", ",")) // [a, b, c]
println(strings.split("one two", " ")) // [one, two]Destructuring the result is the usual way to take a key/value pair apart:
key, value := strings.split("PORT=8080", "=")
println(key, value) // PORT 8080For a pattern delimiter, use regex.split.
#join(arr, delim)
Join an array of strings with a delimiter — the inverse of split.
println(strings.join(["x", "y", "z"], "-")) // x-y-z
println(strings.join(["a", "b"], "")) // ab#lines(s)
Split on newlines. Shorthand for split(s, "\n").
introduce io
introduce strings
each line in strings.lines(io.read_file("notes.txt")) {
println("> " + line)
}#Trimming
#trim(s)
Remove leading and trailing whitespace.
println("[" + strings.trim(" hi ") + "]") // [hi]#strip(s, chars)
Remove any of the characters in chars from both ends. chars is a set of
characters, not a substring.
println(strings.strip("##head##", "#")) // head
println(strings.strip(" --test-- ", " -")) // test#strip_left(s, chars)
Same, left end only.
println(strings.strip_left("--value", "-")) // value#strip_right(s, chars)
Same, right end only.
println(strings.strip_right("value--", "-")) // value#Case
#upper(s)
println(strings.upper("hi")) // HI#lower(s)
println(strings.lower("HI")) // hi#capitalize(s)
Uppercase the first character only; the rest is untouched. An empty string comes back unchanged.
println(strings.capitalize("hello world")) // Hello world
println(strings.capitalize("")) //#Search and replace
#replace(s, old, new)
Replace every occurrence of old.
println(strings.replace("foo bar bar", "bar", "baz")) // foo baz bazFor a pattern, use regex.replace.
#starts_with(s, prefix)
println(strings.starts_with("hello", "he")) // True#ends_with(s, suffix)
println(strings.ends_with("hello", "lo")) // True#contains_str(s, sub) / contains(s, sub)
True if sub appears anywhere in s. The two names are the same function —
contains is the shorter alias.
println(strings.contains_str("hello", "ell")) // True
println(strings.contains("hello", "z")) // False#index_of(s, sub, start?)
Index of the first occurrence of sub at or after index start (default 0),
or -1 if there is none. Indexes count characters, like s[i], not bytes.
println(strings.index_of("hello", "ll")) // 2
println(strings.index_of("hello", "z")) // -1
println(strings.index_of("héllo", "l")) // 2
println(strings.index_of("a-b-c", "-", 2)) // 3To find every occurrence, start each search just past the last one:
s := "a-b-c"
i := strings.index_of(s, "-")
repeat when i != -1 {
println(i) // 1, then 3
i = strings.index_of(s, "-", i + 1)
}#count(s, sub)
Number of non-overlapping occurrences.
println(strings.count("banana", "an")) // 2
println(strings.count("aaaa", "aa")) // 2 <- non-overlapping
println(strings.count("abc", "")) // 0#Slicing and characters
#slice(s, start, end)
Substring from start up to (not including) end. Equivalent to the
s[start:end] operator. An end past the string length is clamped.
println(strings.slice("hello world", 0, 5)) // hello
println(strings.slice("abc", 0, 99)) // abc#char_at(s, i)
The character at index i, as a one-character string.
println(strings.char_at("hello", 1)) // e#is_empty(s)
True when the length is 0.
println(strings.is_empty("")) // True
println(strings.is_empty("x")) // False#byte_len(s)
Length in UTF-8 bytes. len(s) counts characters, which is what indexing and
slicing use; byte counts are for wire formats such as Content-Length.
println(len("héllo")) // 5
println(strings.byte_len("héllo")) // 6#Building
#reverse(s)
Reverse the characters.
println(strings.reverse("hello")) // olleh#repeated(s, n)
s repeated n times. It is not called repeat because that is a loop
keyword.
println(strings.repeated("ab", 3)) // ababab
println(strings.repeated("-", 20)) // --------------------#pad_left(s, width, fill)
Prepend fill until the string is at least width characters long. A string
already at least that long is returned unchanged. An empty fill with a string
shorter than width is an error (it could never reach the width).
println(strings.pad_left("7", 3, "0")) // 007#pad_right(s, width, fill)
Append fill until the string is at least width long — the way to line up
columns.
println(strings.pad_right("7", 3, ".")) // 7..fill may be more than one character, in which case the result can overshoot
width.
#Worked example
introduce strings
// Parse "key: value" config lines into a map, ignoring blanks and comments.
fun parse_config(text <str>) {
out <map> := {}
each line in strings.lines(text) {
trimmed := strings.trim(line)
option {
strings.is_empty(trimmed) -> { None }
strings.starts_with(trimmed, "#") -> { None }
strings.contains(trimmed, ":") -> {
k, v := strings.split(trimmed, ":")
out[strings.trim(k)] = strings.trim(v)
}
}
}
out
}
println(parse_config("# settings\nhost: localhost\nport: 8080\n"))
// {host: localhost, port: 8080}See also: regex for pattern matching, encoding for
base64/hex/URL escaping, and the global builtins len, str, int, float,
chars in builtins.md.