DocsStandard library

Regular expressions.

Search text with checked literal patterns or patterns compiled at runtime.

A regular expression is handy when a text pattern is easier to describe than to build from string operations. Fango uses Go’s RE2-style engine, so lookaround and backreferences aren’t available.

API reference: Regex

Compilation.

import Regex
import Result exposing (Result(..))

main() =
    print (Regex.matches /(?i)hello/ "Hello, Ada")
    case Regex.compile "[a-z]+" of
        Ok pattern -> print (Regex.matches pattern "123abc")
        Err error -> print (Regex.message error)

Both successful tests print True. A literal pattern is checked when the program is compiled and then reused for every match. Regex.compile takes a string at runtime and returns a Result, so an invalid pattern comes back as data you can report.

If you’re building a pattern from arbitrary text, pass that text through Regex.escape first. Otherwise punctuation in it can change what the pattern means.

Matching and captures.

matches searches anywhere in the text. Add ^ and $ if the whole input has to fit the pattern. find gives you the first match along with its location:

import Regex
import String

main() =
    case Regex.find /[0-9]+/ "é:42!" of
        Nothing -> print "not found"
        Just found ->
            print found.text
            print (found.start, found.end)
            print (String.slice found.start found.end "é:42!")
42
(2, 4)
42

Positions count Unicode scalars and the end is exclusive, so they work directly with String.slice. They are not UTF-8 byte offsets.

A match also has captures, which holds the numbered groups but not the whole match. An optional group that didn’t take part is Nothing, while an empty group that did match still has a span. findAll returns every non-overlapping match, in the order they appear.

Replacement and splitting.

You choose whether dollar signs in the replacement refer to captures or stay as plain text:

import Regex

main() =
    print (Regex.replaceAll /([a-z]+)=([0-9]+)/ "$1: $2" "size=12")
    print (Regex.replaceAllLiteral /[0-9]+/ "$1" "size=12")
    print (Regex.split /[,;] */ "red, green;blue")
size: 12
size=$1
["red", "green", "blue"]

replaceAll understands templates such as $1 and ${name}. replaceAllLiteral inserts the replacement exactly as written, which is usually what you want when the replacement text comes from a user.

Regex values are immutable and opaque. Regex.pattern gives you back the original pattern text, but there are no equality or display instances for them.