std.string
String manipulation lives at std.string. A subset of these is also
available as self-operator pipes on strings (e.g. s:upper()) — the seeded
string pipes are upper lower trim trim_left trim_right substr replace replace_first repeat pad_left pad_right plus the dispatch pipes insert erase reverse. See Pipes for the full picture.
Reference
upper(s) lower(s) trim(s) trim_left(s) trim_right(s)
substr(s, start[, length]) char_at(s, index)
char_code(s[, index]) from_char_code(code...)
find(s, pattern) index_of(s, pattern) last_index_of(s, pattern)
contains(s, pattern) starts_with(s, prefix) ends_with(s, suffix)
count(s, pattern)
replace(s, old, new) replace_first(s, old, new)
repeat(s, n) reverse(s) insert(s, index, text) erase(s, start[, length])
pad_left(s, width[, fill]) pad_right(s, width[, fill])
split(s, delimiter[, limit]) join(array[, separator])
is_empty(s) is_alpha(s) is_digit(s) is_alnum(s)
is_upper(s) is_lower(s) is_space(s)
find / index_of / last_index_of return an index or -1 when not found.
count returns 0 when absent. substr's optional third argument is a
length, not an end index; when omitted it runs to the end of the string.
Case and whitespace
print(std.string.upper("hello")) // HELLO
print(std.string.lower("HeLLo")) // hello
print(std.string.trim(" hi ")) // hi (both ends)
print(std.string.trim_left(" hi ")) // "hi " (leading only)
print(std.string.trim_right(" hi ")) // " hi" (trailing only)
// they are pipes too, and chain:
var s = " hello "
print(s:trim():upper()) // HELLO
The whole trim family is commonly used to clean up captured command output —
e.g. std.string.trim(std.system("whoami").output) to strip its trailing
newline.
Searching
All searches are plain substring searches (not regular expressions):
var s = "banana"
std.string.contains(s, "na") // true
std.string.starts_with(s, "ban") // true
std.string.ends_with(s, "ana") // true
std.string.count(s, "na") // 2
std.string.find(s, "na") // 2 (first index)
std.string.index_of(s, "na") // 2 (same)
std.string.last_index_of(s, "na") // 4 (search from the end)
std.string.find(s, "zz") // -1 (not found)
Picking characters and codes
var word = "abc"
std.string.char_at(word, 1) // "b" (1-char string)
std.string.char_code(word) // 97 (first char)
std.string.char_code(word, 1) // 98 (char at index 1)
std.string.from_char_code(72, 105) // "Hi" (codes -> string)
from_char_code accepts any number of codes, so it pairs neatly with char_code
for character arithmetic, e.g. shifting letters, or producing a string from
returned byte codes.
Cutting, joining, and editing
substr extracts a run (length, not end index). replace swaps every
occurrence; replace_first only the first:
var s = "a-b-c"
std.string.substr(s, 1, 3) // "-b-" (3 chars from index 1)
std.string.substr(s, 4) // "c" (to the end)
std.string.replace(s, "-", "+") // "a+b+c"
std.string.replace_first(s, "-", "+") // "a+b-c"
std.string.insert("abc", 1, "XY") // "aXYbc"
std.string.erase("hello", 1, 2) // "hlo" (2 chars from index 1)
std.string.reverse("abc") // "cba"
std.string.repeat("ab", 3) // "ababab"
Splitting and building
std.string.split("a,b,c", ",") // ["a", "b", "c"]
std.string.split("a,b,c,d", ",", 2) // ["a", "b,c,d"] (cap at 2)
std.string.join(["a", "b", "c"]) // "abc" (no separator)
std.string.join(["a", "b"], "-") // "a-b"
// trim + split is the classic CSV / config-line idiom
var line = " name, age, city "
var parts = std.string.split(std.string.trim(line), ",")
print(parts) // ["name", " age", " city"]
std.string.pad_left("7", 3, "0") // "007"
std.string.pad_right("x", 3, ".") // "x.."
Classification
Each is_* test returns a boolean:
std.string.is_digit("5") // true
std.string.is_alpha("a") // true
std.string.is_alnum("a1") // true
std.string.is_space(" ") // true (newline/tab etc. too)
std.string.is_upper("A") // true
std.string.is_lower("a") // true
std.string.is_empty("") // true
Use split plus every from std.sort to check an entire string:
// is every character a digit?
var pin = "1234"
var chars = std.string.split(pin, "") // ["1", "2", "3", "4"]
print(std.sort.every(chars, fn(c) { return std.string.is_digit(c) })) // true