std/string
String search, transform, and inspect operations are methods on any string value — no import needed. The character-class helpers below are free functions imported from std/string.
let name = " Alice "
let clean = name.trim().toLower() // "alice"String methods
Built into the language: the checker dispatches these on any string, so they need no import. Indices are byte offsets unless the note says otherwise.
let parts = "a,b,c".split(",") // ["a", "b", "c"]
match "hello".indexOf("l") {
Some(i) => print(i), // 2
None => print("absent"),
}string method | Notes |
|---|---|
len: i64 | |
isEmpty(): bool | |
contains(needle: string): bool | |
startsWith(prefix: string): bool | |
endsWith(suffix: string): bool | |
indexOf(needle: string): Option<i64> | |
indexOfFrom(needle: string, from: i64): Option<i64> | |
lastIndexOf(needle: string): Option<i64> | |
charAt(i: i64): string | the whole character starting at BYTE offset i: charAt(1) of "aéb" is "é"; an offset inside a multibyte character aborts. Iterate with for c in s.codePoints() for characters |
substr(start: i64, end: i64): string | BYTE offsets — a bound inside a multibyte character splits it and yields invalid UTF-8, silently |
slice(start: i64, end: i64): &string | a view, not a copy — the receiver is frozen while it lives. BYTE offsets, like substr |
toLower(): string | ASCII only — "AÉB" lowercases to "aÉb"; std/unicode's unicodeLower maps every script |
toUpper(): string | ASCII only — "aéb" uppercases to "AéB"; std/unicode's unicodeUpper maps every script |
trim(): string | |
trimStart(): string | |
trimEnd(): string | |
repeat(n: i64): string | |
reverse(): string | code-point aware, unlike charAt/substr — "日本語" reverses to "語本日" |
padStart(targetLen: i64, pad: string): string | targetLen counts characters (code points), so "café" and "cafe" pad to the same column; the pad string is cycled by character |
padEnd(targetLen: i64, pad: string): string | targetLen counts characters, like padStart |
replace(old: string, new: string): string | |
replaceFirst(old: string, new: string): string | |
split(sep: string): Vec<string> | |
splitWords(): Vec<string> | |
splitWhitespace(): Vec<string> | |
lines(): &string pieces | for-in only — yields views into the receiver, never owned copies |
splitView(sep: string): &string pieces | for-in only — yields views into the receiver, never owned copies |
codePoints(): i32 code points | for-in only — a parser desugar, not a value you can bind |
parseInt(): Option<i64> | |
parseF64(): Option<f64> | |
push(c: u8) | |
pushStr(s: &string) | |
pushInt(n: i64) | appends n's decimal digits in place; takes any integer width (u64, i8, ...), no temporary string |
clear() | empties the string, keeping its capacity |
truncate(len: i64) | keeps the first len BYTES and the capacity; len past the end is a no-op, a len inside a multibyte character aborts |
setByte(i: i64, b: u8) | overwrites byte i in place, the write-side twin of s[i]; i outside 0..len aborts. A byte op like s[i]: it does not keep the text valid UTF-8 |
cstr(): *u8 | NUL-terminated pointer to the bytes; the string must outlive it and not be written meanwhile. A string held in a local or its field is made the only handle to its buffer first (copy-on-write), so C may write the bytes in place; through a &string or a global they are read-only |
clone(): string |
Character helpers
The ASCII byte classifiers are free functions in std/string. The prelude imports them into every program, so they need no import either. Each takes a u8.
from "std/string" import { asciiIsWhitespace, asciiIsDigit, asciiIsAlpha, asciiIsAlphanumeric }API reference
asciiIsAlpha
pub fn asciiIsAlpha(ch: u8): boolCheck if a byte is an ASCII letter.
asciiIsAlphanumeric
pub fn asciiIsAlphanumeric(ch: u8): boolCheck if a byte is an ASCII letter or digit.
asciiIsControl
pub fn asciiIsControl(ch: u8): boolasciiIsDigit
pub fn asciiIsDigit(ch: u8): boolCheck if a byte is an ASCII digit.
asciiIsHexDigit
pub fn asciiIsHexDigit(ch: u8): boolasciiIsLower
pub fn asciiIsLower(ch: u8): boolasciiIsPrintable
pub fn asciiIsPrintable(ch: u8): boolasciiIsPunctuation
pub fn asciiIsPunctuation(ch: u8): boolasciiIsUpper
pub fn asciiIsUpper(ch: u8): boolasciiIsWhitespace
pub fn asciiIsWhitespace(ch: u8): boolCheck if a byte is ASCII whitespace.
asciiToLower
pub fn asciiToLower(ch: u8): u8asciiToUpper
pub fn asciiToUpper(ch: u8): u8strContainsIgnoreCase
pub fn strContainsIgnoreCase(haystack: &string, needle: &string): boolTrue if needle occurs anywhere in haystack, ignoring ASCII case.
strIndexOfFromIgnoreCase
pub fn strIndexOfFromIgnoreCase(haystack: &string, needle: &string, pos: i64): i64First occurrence of needle in haystack at or after pos, comparing ASCII letters case-insensitively, or -1.
Same memchr skip as strIndexOfFrom, with two differences that both come from case folding:
- The scan anchors on the first byte of the needle that is NOT a letter. That byte has one spelling, so memchr runs once instead of once per case, and a digit or punctuation byte is rarer in text than a letter, so each call rejects far more. Searching "uint256" case-insensitively anchors on '2', not 'u'. A needle that is all letters falls back to the two-pass scan on byte 0.
- When two passes ARE running, only the one whose hit was just consumed is re-run. Refreshing both after every failed verify re-scans the rest of the buffer per candidate, which is quadratic in candidate count.
The verify is a byte loop rather than strncasecmp: the MSVC CRT spells that _strnicmp, and this file is in the prelude of every program on every platform. It only runs on candidate positions, which memchr has already made rare.