String Utilities
Luma provides comprehensive string manipulation methods that are immutable, safe, and easy to chain.
Declaration
text: str = "Hello World"Quick Reference
| Method | Description | Returns |
|---|---|---|
s.upper() |
Uppercase | str |
s.lower() |
Lowercase | str |
s.title() |
Title Case Each Word | str |
s.trim() |
Strip leading/trailing whitespace | str |
s.trim_left() |
Strip leading whitespace | str |
s.trim_right() |
Strip trailing whitespace | str |
s.pad_left(width) |
Left-pad with spaces to width | str |
s.pad_left(width, char) |
Left-pad with custom character | str |
s.pad_right(width) |
Right-pad with spaces to width | str |
s.pad_right(width, char) |
Right-pad with custom character | str |
s.contains(sub) |
Check if substring exists | bool |
s.starts_with(prefix) |
Check prefix | bool |
s.ends_with(suffix) |
Check suffix | bool |
s.is_empty() |
Check if string is empty | bool |
s.index_of(sub) |
First occurrence index | ?int |
s.last_index_of(sub) |
Last occurrence index | ?int |
s.split(delimiter) |
Split by delimiter | [str] |
s.split() |
Split by whitespace | [str] |
s.chars() |
Split into characters | [str] |
s.replace(old, new) |
Replace all occurrences | str |
s.repeat(n) |
Repeat n times | str |
s.reverse() |
Reverse the string | str |
s.len() |
Length of string | int |
words.join(sep) |
Join a [str] list |
str |
s.regex_match(pattern) |
Test if string matches regex | bool |
s.regex_find(pattern) |
First regex match or nil | ?str |
s.regex_find_all(pattern) |
All regex matches | [str] |
s.regex_replace(pattern, replacement) |
Replace all regex matches | str |
s.regex_split(pattern) |
Split by regex pattern | [str] |
s.from_hex() |
Decode hex string to bytes | [byte] or ?[byte] |
s.from_base64() |
Decode base64 to bytes | [byte] or ?[byte] |
s.from_base64url() |
Decode URL-safe base64 to bytes | [byte] or ?[byte] |
Methods
Case Conversion
text.upper() // "HELLO WORLD"
text.lower() // "hello world"
text.title() // "Hello World"Whitespace Handling
" hello ".trim() // "hello"
" hello ".trim_left() // "hello "
" hello ".trim_right() // " hello"Padding & Alignment
Pad a string to a fixed width. If the string is already equal to or longer than the width, it’s returned unchanged.
"42".pad_left(5) // " 42"
"42".pad_left(5, "0") // "00042"
"hi".pad_right(10) // "hi "
"hi".pad_right(10, ".") // "hi........"pad_left adds padding before the string (right-aligns the content).
pad_right adds padding after the string (left-aligns the content).
The second argument is optional — defaults to a space. When provided, it must be a single character.
// Align numbers in a column
price: str = "9.99"
price.pad_left(10) // " 9.99"
// Fixed-width labels
"Name".pad_right(15) // "Name "
"Age".pad_right(15) // "Age "Useful for terminal tables, columnar output, and formatted reports.
Search & Validation
text.contains("World") // true
text.starts_with("Hello") // true
text.ends_with("World") // true
text.is_empty() // false
text.index_of("World") // 6
text.last_index_of("l") // 9index_of and last_index_of return ?int — they produce nil when the substring is not found:
pos: ?int = "hello".index_of("xyz") // nilLength
"hello".len() // 5
"".len() // 0Splitting & Joining
"a,b,c".split(",") // ["a", "b", "c"]
"one two".split() // ["one", "two"]
"hello".chars() // ["h", "e", "l", "l", "o"].join() is called on a [str] list to combine elements with a separator:
words: [str] = "a,b,c".split(",")
words.join(" - ") // "a - b - c"Replacement & Repetition
text.replace("World", "Luma") // "Hello Luma"
"ha".repeat(3) // "hahaha"Reverse & Characters
"Hello".reverse() // "olleH"
"Hi!".chars() // ["H", "i", "!"]Regex
All regex methods share the regex_ prefix, so they’re easy to find and clearly distinct from plain string operations. Patterns use standard regular expression syntax.
Testing a match
regex_match returns true if the pattern matches anywhere in the string:
"hello123".regex_match("[0-9]+") // true
"hello".regex_match("[0-9]+") // falseUse it for validation:
email: str = "user@example.com"
if email.regex_match("^[^@]+@[^@]+\\.[^@]+$") {
print("valid email format")
}Finding the first match
regex_find returns the first match or nil if nothing matches:
result: ?str = "order-4521-confirmed".regex_find("[0-9]+")
// result = "4521"This pairs naturally with pattern matching:
match "invoice #8832".regex_find("#[0-9]+") {
nil -> print("no invoice number")
id -> print("found: ${id}")
}Finding all matches
regex_find_all returns every match as a list:
numbers: [str] = "a1 b22 c333".regex_find_all("[0-9]+")
// ["1", "22", "333"]Returns an empty list when nothing matches:
"hello".regex_find_all("[0-9]+") // []Replacing matches
regex_replace replaces all occurrences of the pattern:
clean: str = " too many spaces ".regex_replace("\\s+", " ")
// " too many spaces "
redacted: str = "call 555-1234 or 555-5678".regex_replace("[0-9]{3}-[0-9]{4}", "***-****")
// "call ***-**** or ***-****"For literal replacement (no regex), use .replace() instead — it’s simpler and faster.
Splitting by pattern
regex_split splits a string using a regex as the delimiter:
parts: [str] = "one, two; three".regex_split("[,;]\\s*")
// ["one", "two", "three"]For splitting on a fixed delimiter, use .split() instead.
Regex summary
| Method | Returns | Description |
|---|---|---|
s.regex_match(pattern) |
bool |
Does the pattern match anywhere? |
s.regex_find(pattern) |
?str |
First match, or nil |
s.regex_find_all(pattern) |
[str] |
All matches |
s.regex_replace(pattern, repl) |
str |
Replace all matches |
s.regex_split(pattern) |
[str] |
Split by pattern |
Error handling
An invalid regex pattern causes a panic at runtime:
"test".regex_match("[invalid") // panic: invalid regexAlways use valid patterns. Regex patterns are compiled each time a method is called — for hot loops, this is a known cost.
Practical examples
Log line parsing
line: str = "2026-02-14 ERROR: connection refused"
match line.regex_find("^[0-9]{4}-[0-9]{2}-[0-9]{2}") {
nil -> print("no date found")
date -> print("log date: ${date}")
}
level: str = match line.regex_find("(ERROR|WARN|INFO|DEBUG)") {
nil -> "UNKNOWN"
l -> l
}Input sanitization
fn sanitize(input: str) -> str {
return input
.regex_replace("[<>\"']", "")
.trim()
}Tokenizing
source: str = "name=alice age=30 role=admin"
pairs: [str] = source.regex_find_all("[a-z]+=\\w+")
// ["name=alice", "age=30", "role=admin"]Encoding
Strings can decode encoded text back to [byte].
Hex Decoding
data: [byte] = "48656c6c6f".from_hex()
data: ?[byte] = user_input.from_hex() // nil for invalid hexDecodes a hexadecimal string to bytes. Panics on invalid input (odd length, non-hex characters).
Use ?[byte] for safe decoding that returns nil instead.
Base64 Decoding
data: [byte] = "SGVsbG8=".from_base64()
data: ?[byte] = user_input.from_base64() // nil for invalid base64Decodes standard base64 (RFC 4648) back to bytes.
URL-Safe Base64 Decoding
data: [byte] = "SGVsbG8".from_base64url()
data: ?[byte] = user_input.from_base64url() // nil for invalidDecodes URL-safe base64 (no padding, - and _ instead of + and /).
Encoding Summary
| Method | Returns | Description |
|---|---|---|
s.from_hex() |
[byte] or ?[byte] |
Hex string to bytes |
s.from_base64() |
[byte] or ?[byte] |
Base64 string to bytes |
s.from_base64url() |
[byte] or ?[byte] |
URL-safe base64 to bytes |
To encode bytes as text, use the corresponding methods on [byte] — see Lists.
// Decode a hex-encoded key
key: [byte] = "deadbeef".from_hex()
// Safe decode from user input
input: str = "not valid hex!!"
data: ?[byte] = input.from_hex()
if data == nil {
print("Invalid hex string")
}Chaining
All string methods that return str can be chained:
name: str = " john doe "
clean_name = name.trim().title() // "John Doe"
loud = " hello world ".trim().upper() // "HELLO WORLD"Examples
Validation
email: str = "user@example.com"
// Simple check
if !email.contains("@") {
error("Invalid email")
}
// Regex check
if !email.regex_match("^[^@]+@[^@]+\\.[^@]+$") {
error("Invalid email format")
}CSV Parsing
data: str = "apple,123,true"
parts = data.split(",")
name = parts[0] // "apple"
count = parts[1].to_int(0) // 123
active = parts[2].to_bool(false) // trueBuilding Output
tags: [str] = "rust,go,luma".split(",")
output: str = tags.join(", ") // "rust, go, luma"Notes
- All string methods return new strings (strings are immutable)
- Methods like
index_ofandlast_index_ofreturn?int(nullable) .join()is a list method that works on[str]lists- Conversion methods (
to_int,to_float,to_bool) require default values for error cases