String Methods¶
Comprehensive string manipulation methods. Sushi strings are UTF-8 encoded fat pointers {i8* data, i32 size}.
String Literals¶
Sushi supports two string literal syntaxes:
- Double quotes (
"..."): Support interpolation with{expr}syntax - Single quotes (
'...'): Plain string literals, no interpolation
Both support the same escape sequences (\n, \t, \\, \', \", \xNN, \uNNNN). Single-quote strings are particularly useful as arguments inside interpolation expressions.
let string s1 = "double quotes" # With interpolation
let string s2 = 'single quotes' # No interpolation
println("{s1.pad_left(20, '*')}") # Single quotes for args
Import¶
use <collections/strings>
Overview¶
All string methods are immutable and return new strings. The stdlib provides 33 string methods covering: - Inspection: len, size, is_empty, contains, starts_with, ends_with, find, find_last, count - Slicing: s, ss, sleft, sright, char_at - Transformation: upper, lower, cap, reverse, repeat, replace, trim, tleft, tright - Padding: pad_left, pad_right - Stripping: strip_prefix, strip_suffix - Splitting/Joining: split, join - Conversion: to_bytes, to_i32, to_i64, to_f64 - Concatenation: concat
Inspection Methods¶
.len() -> i32¶
Character count (UTF-8 aware).
let string s = "Hello 🌍"
println(s.len()) # 7 characters
.size() -> i32¶
Byte count.
println(s.size()) # 10 bytes
.is_empty() -> bool¶
Check if string is empty.
if (s.is_empty()):
println("Empty string")
.contains(string needle) -> bool¶
Check if string contains substring.
let string text = "hello world"
if (text.contains('world')):
println("Found!")
.starts_with(string prefix) -> bool¶
Check if string starts with prefix.
let string path = "/home/user"
if (path.starts_with("/home")):
println("Home directory")
.ends_with(string suffix) -> bool¶
Check if string ends with suffix.
let string filename = "document.txt"
if (filename.ends_with(".txt")):
println("Text file")
.find(string needle) -> Maybe<i32>¶
Find first occurrence position (UTF-8 character index).
match text.find('world'):
Maybe.Some(pos) ->
println("Found at {pos}")
Maybe.None() ->
println("Not found")
.find_last(string needle) -> Maybe<i32>¶
Find last occurrence position (UTF-8 character index).
let string text = "hello world hello"
match text.find_last('hello'):
Maybe.Some(pos) ->
println("Last at {pos}") # 12
Maybe.None() ->
println("Not found")
.count(string needle) -> i32¶
Count non-overlapping occurrences.
let string text = "hello world"
println(text.count("l")) # 3
println(text.count("oo")) # 0
Slicing Methods¶
.sleft(i32 n) -> string¶
Get first n UTF-8 characters.
let string text = "hello"
println(text.sleft(3)) # "hel"
let string utf8 = "café"
println(utf8.sleft(3)) # "caf"
.sright(i32 n) -> string¶
Get last n UTF-8 characters.
let string text = "hello"
println(text.sright(3)) # "llo"
.char_at(i32 index) -> string¶
Get UTF-8 character at index.
let string text = "hello"
println(text.char_at(0)) # "h"
println(text.char_at(4)) # "o"
.s(i32 start, i32 end) -> string¶
Slice by UTF-8 character indices.
let string text = "hello world"
println(text.s(0, 5)) # "hello"
println(text.s(6, 11)) # "world"
.ss(i32 start, i32 length) -> string¶
Substring by byte offset and length.
let string text = "hello"
println(text.ss(0, 3)) # "hel"
println(text.ss(2, 3)) # "llo"
Case Conversion¶
.upper() -> string¶
Convert to uppercase (ASCII only).
let string loud = "hello".upper() # "HELLO"
.lower() -> string¶
Convert to lowercase (ASCII only).
let string quiet = "HELLO".lower() # "hello"
.cap() -> string¶
Capitalize first character.
let string name = "alice"
println(name.cap()) # "Alice"
Transformation Methods¶
.reverse() -> string¶
Reverse string preserving UTF-8 characters.
let string s = "hello"
println(s.reverse()) # "olleh"
let string utf8 = "café"
println(utf8.reverse()) # "éfac"
.repeat(i32 n) -> string¶
Repeat string n times.
let string s = "abc"
println(s.repeat(3)) # "abcabcabc"
println("*".repeat(10)) # "**********"
.replace(string old, string new) -> string¶
Replace all occurrences.
let string text = "hello world"
println(text.replace('world', 'there')) # "hello there"
let string censored = "damn damn".replace('damn', '****')
println(censored) # "**** ****"
# Works beautifully in interpolation:
println("{text.replace('world', 'there')}")
.concat(string other) -> string¶
Concatenate strings.
let string greeting = "Hello".concat(" World")
println(greeting) # "Hello World"
Whitespace Trimming¶
.trim() -> string¶
Remove leading/trailing whitespace.
let string clean = " hello ".trim() # "hello"
.tleft() -> string¶
Remove leading whitespace.
let string clean = " hello".tleft() # "hello"
.tright() -> string¶
Remove trailing whitespace.
let string clean = "hello ".tright() # "hello"
Padding Methods¶
.pad_left(i32 width, string char) -> string¶
Pad to width by prepending character.
let string s = "42"
println(s.pad_left(5, '0')) # "00042"
let string name = "Alice"
println(name.pad_left(10, ' ')) # " Alice"
# Great in interpolation:
println("{s.pad_left(5, '0')}")
.pad_right(i32 width, string char) -> string¶
Pad to width by appending character.
let string s = "42"
println(s.pad_right(5, '0')) # "42000"
Stripping Methods¶
.strip_prefix(string prefix) -> string¶
Remove prefix if present.
let string path = "/home/user/file.txt"
println(path.strip_prefix("/home/user/")) # "file.txt"
let string text = "hello"
println(text.strip_prefix("bye")) # "hello" (unchanged)
.strip_suffix(string suffix) -> string¶
Remove suffix if present.
let string filename = "document.txt"
println(filename.strip_suffix(".txt")) # "document"
let string text = "hello"
println(text.strip_suffix("bye")) # "hello" (unchanged)
Splitting and Joining¶
.split(string delimiter) -> string[]¶
Split into array.
let string[] parts = "a,b,c".split(',')
# parts = ["a", "b", "c"]
# In interpolation:
println("Parts: {text.split(',')}")
.join(string[] parts) -> string¶
Join array with separator.
let string[] words = from(["a", "b", "c"])
println(','.join(words)) # "a,b,c"
println(''.join(words)) # "abc"
# Single quotes shine in interpolation:
println("{','.join(words)}")
Conversion Methods¶
.to_bytes() -> u8[]¶
Convert to byte array.
let string text = "Hi"
let u8[] bytes = text.to_bytes()
# bytes = [72, 105]
The inverse conversions are u8[] methods (core, no import):
bytes.to_string() (zero-cost, assumes valid UTF-8) and
bytes.to_string_checked() -> Result<string, StdError> (validates UTF-8, Result.Err on
malformed input).
.to_i32() -> Maybe<i32>¶
Parse to i32.
match "42".to_i32():
Maybe.Some(n) ->
println("Parsed: {n}")
Maybe.None() ->
println("Invalid number")
.to_i64() -> Maybe<i64>¶
Parse to i64.
let Maybe<i64> result = "9223372036854775807".to_i64()
.to_f64() -> Maybe<f64>¶
Parse to f64.
match "3.14".to_f64():
Maybe.Some(pi) ->
println("Pi: {pi}")
Maybe.None() ->
println("Invalid float")
Best Practices¶
- All methods are immutable (return new strings)
- Use
.len()for character count,.size()for byte count - UTF-8 aware methods: len, sleft, sright, char_at, s, find, find_last
- Byte-based methods: ss, size, contains, starts_with, ends_with
- Case conversion is ASCII-only (upper, lower, cap)
- Use
.realise()or pattern matching to handle Maybe results from find/parse