regex

Regular expression functions. Pattern strings use standard regex syntax.

Every function takes the text first and the pattern second, so a text pipes into them (line |> regex.split("\\s+")), and returns a Result: a pattern is text like any other, and one that is no pattern is Err(RegexError), not a failure of the program.

import regex

fn main() {
  match regex.find("abc 123", "(") {
    Ok(found) -> println(found)
    Err(regex.InvalidPattern(why, at)) -> println("{why} at {at}") -- unclosed group at 0
    Err(e) -> println(e.message())
  }
}
open in playground
VariantFieldsMeaning
InvalidPattern(String, Int)what is wrong, and the character of the pattern where: counted from 0, as string.slice counts. It is the pattern’s length when the fault is that the pattern ends therethe pattern does not parse
TooBig—the compiled pattern exceeds the size budget
Other(String)messageunclassified failure

With a pattern the program writes itself, the error cannot happen, and result.unwrap_or says what the call is worth if it did: regex.is_match(name, "^[a-z]+$") |> result.unwrap_or(false).

Summary

FunctionSignatureDescription
captures(String, String) -> Result(Option(List(String)), RegexError)Capture groups from first match
captures_all(String, String) -> Result(List(List(String)), RegexError)Capture groups from all matches
captures_named(String, String) -> Result(Option(Map(String, String)), RegexError)Named capture groups from first match
find(String, String) -> Result(Option(String), RegexError)First match
find_all(String, String) -> Result(List(String), RegexError)All matches
is_match(String, String) -> Result(Bool, RegexError)Test if pattern matches
replace(String, String, String) -> Result(String, RegexError)Replace first match
replace_all(String, String, String) -> Result(String, RegexError)Replace all matches
replace_all_with(String, String, Fn(String) -> String) -> Result(String, RegexError)Replace all with callback
split(String, String) -> Result(List(String), RegexError)Split on pattern

regex.captures

regex.captures(text: String, pattern: String) -> Result(Option(List(String)), RegexError)

Returns capture groups from the first match, or None if no match. The full match is at index 0, followed by numbered groups.

import list
import regex

fn main() {
  match regex.captures("user@host", "(\\w+)@(\\w+)") {
    Ok(Some(groups)) -> {
      println(list.get(groups, 1)) -- Some(user)
      println(list.get(groups, 2)) -- Some(host)
    }
    Ok(None) -> println("no match")
    Err(e) -> println(e.message())
  }
}
open in playground

regex.captures_all

regex.captures_all(text: String, pattern: String) -> Result(List(List(String)), RegexError)

Returns capture groups for every match. Each inner list has the full match at index 0 followed by numbered groups.

import regex

fn main() {
  println(regex.captures_all("1-2 and 3-4", "(\\d+)-(\\d+)"))
  -- Ok([[1-2, 1, 2], [3-4, 3, 4]])
}
open in playground

regex.captures_named

regex.captures_named(text: String, pattern: String) -> Result(Option(Map(String, String)), RegexError)

Returns a map of named capture groups from the first match. Named groups use the (?P<name>...) syntax.

  • Returns None if the pattern has no named groups or if it does not match.
  • A named group that is present in the pattern but did not participate in the match (e.g. inside an optional (...)?) is omitted from the map — it is not mapped to "".
  • Unnamed numbered groups are ignored; use regex.captures for positional access.
import map
import regex

fn main() {
  match regex.captures_named("alice@example", "(?P<user>\\w+)@(?P<host>\\w+)") {
    Ok(Some(groups)) -> {
      println(map.get(groups, "user")) -- Some(alice)
      println(map.get(groups, "host")) -- Some(example)
    }
    Ok(None) -> println("no match")
    Err(e) -> println(e.message())
  }
}
open in playground

regex.find

regex.find(text: String, pattern: String) -> Result(Option(String), RegexError)

Returns Some(matched_text) for the first match, or None.

import regex

fn main() {
  println(regex.find("abc 123 def", "\\d+")) -- Ok(Some(123))
  println(regex.find("abc", "\\d+")) -- Ok(None)
}
open in playground

regex.find_all

regex.find_all(text: String, pattern: String) -> Result(List(String), RegexError)

Returns all non-overlapping matches as a list of strings.

import regex

fn main() {
  println(regex.find_all("a1 b22 c333", "\\d+")) -- Ok([1, 22, 333])
}
open in playground

regex.is_match

regex.is_match(text: String, pattern: String) -> Result(Bool, RegexError)

Returns true if the pattern matches anywhere in the text.

import regex

fn main() {
  println(regex.is_match("123", "^\\d+$")) -- Ok(true)
  println(regex.is_match("abc", "^\\d+$")) -- Ok(false)
}
open in playground

regex.replace

regex.replace(text: String, pattern: String, replacement: String) -> Result(String, RegexError)

Replaces the first match with the replacement string.

import regex

fn main() {
  println(regex.replace("abc 123 def 456", "\\d+", "NUM")) -- Ok(abc NUM def 456)
}
open in playground

regex.replace_all

regex.replace_all(text: String, pattern: String, replacement: String) -> Result(String, RegexError)

Replaces all matches with the replacement string.

import regex

fn main() {
  println(regex.replace_all("abc 123 def 456", "\\d+", "NUM")) -- Ok(abc NUM def NUM)
}
open in playground

regex.replace_all_with

regex.replace_all_with(text: String, pattern: String, f: Fn(String) -> String) -> Result(String, RegexError)

Replaces all matches by calling f with each matched text. The callback must return a string.

import int
import regex
import result
import string

fn main() {
  let doubled = regex.replace_all_with("a1 b22 c333", "\\d+") { m ->
    let n = int.parse(m) |> result.unwrap_or(0)
    string.from(n * 2)
  }
  println(doubled) -- Ok(a2 b44 c666)
}
open in playground

regex.split

regex.split(text: String, pattern: String) -> Result(List(String), RegexError)

Splits the text on every occurrence of the pattern.

import regex
import result

fn main() {
  let parts = "hello   world   silt" |> regex.split("\\s+") |> result.unwrap_or([])
  println(parts) -- [hello, world, silt]
}
open in playground