Skip to content

Strings

Work with UTF-8 text, characters, and borrowed substrings.

Updated View as Markdown

string is owned UTF-8 text and char is one Unicode scalar value. Atoll keeps character positions and encoded-byte positions distinct.

name := "Ångström"
characters := name.length()
encoded := name.len()
first := name.char_at(0)

length() walks the UTF-8 buffer and counts Unicode scalars. len() reads the encoded byte length; byte_length() is its deprecated alias. For non-ASCII text, the byte length can be larger than the character count.

char_at, first, and last return Option[char], so empty and out-of-range access cannot panic.

Searching

if path.starts_with("/api/") && path.ends_with(".json") {
    use(path)
}

position := text.index_of("needle")

The search surface includes contains, starts_with, ends_with, index_of, and last_index_of. Missing positions are None; successful positions use character indexes rather than raw byte offsets.

Use equals_ignore_case and compare_to_ignore_case when case-insensitive comparison is the intended contract. Ordinary == remains content equality.

Slicing

substring(start, end) and slice(range) are byte-indexed and return substring?, a borrowed byte view into the original string:

match text.substring(0, 5) {
    Some(view) => consume(view.to_string())
    None => report_bad_range()
}

An out-of-bounds range returns None. The current operation does not check that both endpoints are Unicode character boundaries. Only convert or interpret the view as text when the byte range is known to be aligned.

The view provides byte length, nested slicing, byte access, owned conversion, and Bytes behavior. It borrows the parent buffer; use to_string() or to_bytes() when the result must own its storage.

take, take_last, drop, and drop_last use character counts and return owned strings.

Transformation

Transformation methods fall into a few groups:

  • to_upper_case, to_lower_case, and ASCII-only case conversion;
  • capitalize, title_case, trimming, padding, and repetition;
  • replace, replace_first, and reversed;
  • split, split_with_limit, lines, words, and chars;
  • character map, filter, any, all, none, and fold.
label := input.trim().to_lower_case()
parts := label.split("-")

split_with_limit bounds the number of pieces. enumerate() pairs each character with its character index. count(predicate) counts matching characters rather than substring occurrences.

Conversion

to_int, to_float, and to_bool return Option. to_list produces characters. to_bytes copies into []byte; bytes() returns a borrowed byte slice.

string.from_bytes(bytes) validates UTF-8 and returns string?. string.from_chars(chars) and string.join(items, separator) construct text.

match string.from_bytes(packet) {
    Some(text) => process(text)
    None => reject_invalid_utf8()
}

Use the optional parsers for untrusted text. They return None rather than choosing a fallback or throwing a hidden parsing exception.

Characters

char supports Unicode classification such as is_digit, is_alphabetic, is_alphanumeric, and is_whitespace, plus case conversion and u32/int conversion. char.from_u32 rejects invalid Unicode scalar values:

match char.from_u32(codepoint) {
    Some(value) => println(value.to_string())
    None => report_invalid_codepoint(codepoint)
}

Availability

The prelude contains some declared string operations whose pure-Atoll bodies or backend lowering are still being migrated. Core length, byte access, UTF-8 conversion, searching, ASCII case conversion, equality, and hashing paths are implementation-backed. Before relying on a less common transformation at a deployment boundary, keep a focused compiler/runtime test for that method. A visible prelude signature alone does not guarantee every backend supports the operation yet.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close