Regular expressions
Find, test, and replace text with patterns.
On this page
valk.regex matches text against a pattern. Compile a pattern once with Regex.new, then reuse it.
Find a match#
use valk.regex
fn main() {
let numbers = regex.Regex.new("\\d+") ! {
println("Invalid pattern")
return
}
let found = numbers.find("Order 42 shipped") ?! return
println(found.str()) // 42
println(found.start) // 6
println(found.end) // 8
}
find returns the first match or null. A backslash is doubled inside a Valk string, so \d+ is written "\\d+". Offsets are byte offsets into the text.
Find all, replace, split, test#
use valk.regex
fn main() {
let words = regex.Regex.new("[a-z]+") ! return
each words.find_all("one two three") as found {
println(found.str())
}
let digits = regex.Regex.new("\\d") ! return
println(digits.replace("a1b2", "#")) // a#b#
println(digits.is_match("abc")) // false
let comma = regex.Regex.new("\\s*,\\s*") ! return
println(comma.split("a , b,c").length) // 3
}
| Method | Returns |
|---|---|
find(text, start) |
First match at or after start, or null |
find_all(text, limit) |
Every match, left to right (limit 0 means all) |
match_at(text, start) |
A match that begins exactly at start, or null |
is_match(text) |
Whether the pattern occurs anywhere |
replace(text, replacement, limit) |
Text with matches replaced |
replace_with(text, func, limit) |
Text with each match replaced by what func returns |
split(text) |
The parts between matches |
For a one-off check, regex.is_match(pattern, text) compiles and matches in one call.
Groups#
use valk.regex
fn main() {
let mail = regex.Regex.new("(?P<user>\\w+)@(?P<host>[\\w.]+)") ! return
let found = mail.find("mail me@example.com today") ?! return
println(found.get(1) ?? "") // me
println(found.named("host") ?? "") // example.com
println(mail.replace("me@home you@work", "${host}:${user}")) // home:me work:you
}
Group 0 is the whole match. get and named return null for a group that did not take part. A replacement refers to groups as $1 or ${name}.
Replace with a function#
use valk.regex
fn main() {
let word = regex.Regex.new("\\b[a-z]") ! return
let title = word.replace_with("hello big world", fn(m: regex.Match) String {
return m.str().upper()
})
println(title) // Hello Big World
}
Flags and escaping#
use valk.regex
fn main() {
let yes = regex.Regex.new("^yes$", "im") ! return
println(yes.is_match("no\nYES")) // true
println(regex.escape("1+1=2")) // 1\+1=2
}
The flags are i (ignore case), m (^ and $ match at line boundaries) and s (. matches a newline). Inline flags such as (?i) work too. regex.escape makes text match literally.
Syntax#
- Classes:
.,[a-z],[^...],\d \w \sand\D \W \S,[[:alpha:]] - Anchors:
^ $ \A \z, word boundaries\b \B - Groups:
(...),(?:...),(?P<name>...),(?<name>...) - Quantifiers:
* + ? {n} {n,} {n,m}, add?for lazy matching - Alternation
|, leftmost first:a|abonabmatchesa
Matching never backtracks, so a pattern from user input cannot make the program hang. Backreferences, lookaround and \p{...} are not supported: Regex.new throws unsupported, and a malformed pattern throws syntax.

