Skip to Content
i documentation
Standard library referenceModules

std/string

Functions for String, the type of lists of Unicode scalar values kept as UTF-8.

Lengths, indexes, and slices count codepoints (Unicode scalar values), not bytes and not graphemes: "é" written as e and a combining accent is two codepoints. byte_size counts UTF-8 bytes.

Access and searches count scalars. Negative at indexes count from the end, as in slice; search bounds must be between zero and length. Access, taking and traversals decode once, costing O(bytes) time and O(scalars) cells, even for early access. Searches decode both strings and use naive matching: O(n*m) comparisons and O(n+m) cells. Int arithmetic and callbacks add their costs. No grapheme or normalization policy.

to_upper, to_lower, and capitalise use the simple case mappings of Unicode (core.to_upper and core.to_lower): each codepoint changes to one codepoint, with no locale, so "ß" stays "ß". trim and the other trim functions take out the characters of Unicode Pattern_White_Space: U+0009 to U+000D, U+0020, U+0085, U+200E, U+200F, U+2028, and U+2029.

length

The number of codepoints.

string.length("héllo")  // 5
length = (string : String) -> Int { list.length(core.codepoints(string)) }

byte_size

The number of UTF-8 bytes.

string.byte_size("héllo")  // 6
byte_size = (string : String) -> Int { core.byte_size(string) }

is_empty

True for "".

is_empty = (string : String) -> Bool { string == "" }

concat

The strings one after the other.

concat = (strings : List(String)) -> String { core.concat(strings) }

append

to and then suffix, as a function.

append = (to : String, suffix : String) -> String { to <> suffix }

join

The strings with with between every two of them.

string.join(["a", "b", "c"], ", ")  // "a, b, c"
join = (strings : List(String), with : String) -> String {

repeat

The string times times, one after the other. "" when times is 0 or less.

repeat = (string : String, times : Int) -> String {

split

Cuts a string at every place where on is, and takes out on. With on as "", it cuts between every two codepoints.

string.split("a,b,,c", ",")  // ["a", "b", "", "c"]
string.split("abc", "")      // ["a", "b", "c"]
split = (string : String, on : String) -> List(String) {

split_once

Cuts a string in two at the first place where on is, and takes out on. None when on is not in the string, or is "".

string.split_once("key=value=x", "=")  // Some(("key", "value=x"))
split_once = (string : String, on : String) -> Option((String, String)) {

lines

Cuts a string into lines, at "\n" and at "\r\n".

string.lines("a\nb\r\nc")  // ["a", "b", "c"]
lines = (string : String) -> List(String) {

trim

The string without white space at the start and at the end.

string.trim("  hi \n")  // "hi"
trim = (string : String) -> String { trim_end(trim_start(string)) }

trim_start

The string without white space at the start.

trim_start = (string : String) -> String {

trim_end

The string without white space at the end.

trim_end = (string : String) -> String {

starts_with

True when the string starts with prefix.

starts_with = (string : String, prefix : String) -> Bool {

ends_with

True when the string ends with suffix.

ends_with = (string : String, suffix : String) -> Bool {

contains

True when contain is somewhere in the string. Every string contains "".

string.contains("theory", "ory")  // True
contains = (does : String, contain : String) -> Bool {

replace

Puts with in the place of every each in the string. When each is "", the string is the same.

string.replace("www.example.com", ".", "-")  // "www-example-com"
replace = (in : String, each : String, with : String) -> String {

slice

length codepoints from the codepoint at at_index, counting from 0. A negative index counts from the end: -1 is the last codepoint. The slice stops at the end of the string. A negative length gives "".

string.slice("hello", 1, 2)   // "el"
string.slice("hello", -3, 2)  // "ll"
slice = (string : String, at_index : Int, length : Int) -> String {

drop_start

The string without its first up_to codepoints.

drop_start = (from : String, up_to : Int) -> String {

drop_end

The string without its last up_to codepoints.

drop_end = (from : String, up_to : Int) -> String {

first

The first codepoint, as a string, or None for "".

first = (string : String) -> Option(String) {

last

The last codepoint, as a string, or None for "".

last = (string : String) -> Option(String) {

pop_codepoint

The first codepoint, as a string, and the rest, or None for "".

string.pop_codepoint("abc")  // Some(("a", "bc"))
pop_codepoint = (string : String) -> Option((String, String)) {

crop

The string from the first place where before is. When before is not there, the string is the same.

string.crop("The Lone Ranger", "Lone")  // "Lone Ranger"
crop = (from : String, before : String) -> String {

remove_prefix

The string without prefix at its start. When it does not start with prefix, the string is the same.

string.remove_prefix("@lpil", "@")  // "lpil"
remove_prefix = (from : String, matching : String) -> String {

remove_suffix

The string without suffix at its end. When it does not end with suffix, the string is the same.

remove_suffix = (from : String, matching : String) -> String {

to_upper

The string with every codepoint in upper case, by the simple uppercase mapping of Unicode. A codepoint with no such mapping, such as ß, stays as it is.

string.to_upper("héllo")  // "HÉLLO"
string.to_upper("straße")  // "STRAßE"
to_upper = (string : String) -> String { core.to_upper(string) }

to_lower

The string with every codepoint in lower case, by the simple lowercase mapping of Unicode.

string.to_lower("ΑΒΓ")  // "αβγ"
to_lower = (string : String) -> String { core.to_lower(string) }

capitalise

The first codepoint in upper case and the rest in lower case.

string.capitalise("mamouna")  // "Mamouna"
capitalise = (string : String) -> String {

reverse

The codepoints in the other order.

string.reverse("abc")  // "cba"
reverse = (string : String) -> String { from_reversed(core.codepoints(string)) }

pad_left

Puts with, repeated, before the string until it has to codepoints. The last copy of with may be cut. A string that is long enough stays.

string.pad_left("121", 5, ".")  // "..121"
string.pad_left("121", 6, "XY")  // "XYX121"
pad_left = (string : String, to : Int, with : String) -> String {

pad_right

Puts with, repeated, after the string until it has to codepoints. The last copy of with may be cut. A string that is long enough stays.

pad_right = (string : String, to : Int, with : String) -> String {

to_codepoints

The codepoints of the string, in order.

to_codepoints = (string : String) -> List(UtfCodepoint) {

from_codepoints

The string of these codepoints.

from_codepoints = (codepoints : List(UtfCodepoint)) -> String {

to_codepoint_strings

Every codepoint as a string of its own.

string.to_codepoint_strings("hé")  // ["h", "é"]
to_codepoint_strings = (string : String) -> List(String) {

utf_codepoint

The codepoint with this number, or Error(Nil) when it is not a Unicode scalar value (0 to 0x10FFFF, but not 0xD800 to 0xDFFF).

utf_codepoint = (value : Int) -> Result(UtfCodepoint, Nil) {

utf_codepoint_to_int

The number of a codepoint.

utf_codepoint_to_int = (codepoint : UtfCodepoint) -> Int {

compare

Compares two strings by their codepoints, one by one. This is also the order of their UTF-8 bytes.

string.compare("Anthony", "Anthony")  // Equal
string.compare("A", "B")              // Less
compare = (a : String, b : String) -> Order {

inspect

The text form of any value, as i source (§11.8).

string.inspect([1, 2])  // "[1, 2]"
string.inspect("a")     // "\"a\""
inspect = <A>(term : A) -> String { core.inspect(term) }

to_option

None for "", and Some(string) for any other string.

to_option = (string : String) -> Option(String) {

at

One scalar as a string. Negative indexes count from the end; indexes outside the string, including very negative ones, give None.

at = (string : String, index : Int) -> Option(String) {

index_of

Least full starting scalar index >= from; bounds must be in [0,length]. Empty find matches from. Overlaps are eligible.

index_of = (string : String, find : String, from : Int) -> Option(Int) {

last_index_of

Greatest full starting scalar index <= from; the match may end after from. Empty find matches from; negative or past-end bounds give None.

last_index_of = (string : String, find : String, from : Int) -> Option(Int) {

count

Left-to-right nonoverlapping matches. Empty find has count zero.

count = (string : String, find : String) -> Int {

take_start

First up_to scalars, clamping the count to [0,length].

take_start = (from : String, up_to : Int) -> String {

take_end

Last up_to scalars, clamping the count to [0,length].

take_end = (from : String, up_to : Int) -> String {

split_once_last

Cuts at the last full separator, omitting it. Missing or empty on gives None. Separators at either end leave an empty component.

split_once_last = (string : String, on : String) -> Option((String, String)) {

replace_n

Replaces the first max(0,up_to) nonoverlapping matches. Empty each is a no-op, and inserted text is never searched. Collects and concatenates once.

replace_n = (in : String, each : String, with : String, up_to : Int) -> String {

split_when

Calls on once per scalar, left to right. True separates pieces; separator runs collapse and empty pieces are omitted. Errors stop traversal at once.

split_when = <E, N>(

words

Splits on Pattern_White_Space, as trim does. NBSP is not a separator.

words = (string : String) -> List(String) { split_when(string, is_space) }

map

Calls with once per scalar in order, producing one scalar per input.

map = <N>(

filter

Calls keeping once per scalar in order. Errors stop later calls.

filter = <N>(string : String, keeping : (UtfCodepoint) <- N -> Bool) -> String {

fold

Folds left to right with (accumulator,scalar); empty input gives from.

fold = <A, N>(