regexp

Guided tour · Formatting & Strings · pkg.go.dev →

RE2 regular expressions. Guaranteed linear time — no catastrophic backtracking.

RE2-flavored regular expressions — linear-time, no backreferences. For simple substring matches use strings.Contains; for splitting on whitespace strings.Fields. Compile patterns once at package init.

Compile (panics on bad pattern)
var hex = regexp.MustCompile(`^[0-9a-f]+$`)
Match boolean
if hex.MatchString(s) { ... }
Find first match
m := re.FindString(s)
Find all matches
all := re.FindAllString(s, -1)
Capture groups
m := re.FindStringSubmatch(s)
// m[0] full, m[1] first group...
Replace with template
out := re.ReplaceAllString(s, "$1-$2")

Compile vs MustCompile

Compile returns (*Regexp, error). MustCompile panics on bad patterns — use it for constant patterns at program start.

MustCompile — constant pattern

var emailRe = regexp.MustCompile(`^[^@\s]+@[^@\s]+\.[^@\s]+$`)

fmt.Println(emailRe.MatchString("a@b.co"))  // true
fmt.Println(emailRe.MatchString("nope"))    // false
Output
true
false

Compile — pattern from untrusted input

re, err := regexp.Compile(userPattern)
if err != nil {
    return fmt.Errorf("bad pattern: %w", err)
}

Find family — 16 variants with a pattern

Method names follow: Find[All][String][Submatch][Index]. Think of it as four axes. All = return every match. String = work on strings rather than []byte. Submatch = include capture groups. Index = return offsets instead of matched text.

FindString / FindAllString

re := regexp.MustCompile(`\d+`)
fmt.Println(re.FindString("abc 12 def 34"))      // "12"
fmt.Println(re.FindAllString("abc 12 def 34", -1)) // ["12" "34"]
fmt.Println(re.FindAllString("a1 b2 c3", 2))      // ["1" "2"] — cap at 2
Output
12
[12 34]
[1 2]

FindStringSubmatch — capture groups

re := regexp.MustCompile(`(\w+)=(\w+)`)
m := re.FindStringSubmatch("name=ada")
// m[0] = whole match, m[1..] = groups
fmt.Println(m[0], m[1], m[2])
Output
name=ada name ada

Named groups + SubexpIndex

re := regexp.MustCompile(`(?P<key>\w+)=(?P<val>\w+)`)
m := re.FindStringSubmatch("name=ada")
fmt.Println(m[re.SubexpIndex("key")], m[re.SubexpIndex("val")])
Output
name ada

FindStringIndex — positions instead of text

re := regexp.MustCompile(`\d+`)
loc := re.FindStringIndex("abc 12 def")
fmt.Println(loc)        // [4 6]
fmt.Println("abc 12 def"[loc[0]:loc[1]])
Output
[4 6]
12

Replace

ReplaceAllString

re := regexp.MustCompile(`\s+`)
fmt.Println(re.ReplaceAllString("hi   there\tworld", " "))
Output
hi there world

ReplaceAllString with $1 references

re := regexp.MustCompile(`(\w+)@(\w+)`)
fmt.Println(re.ReplaceAllString("ada@example", "$2.$1"))
Output
example.ada

ReplaceAllStringFunc — custom per-match

re := regexp.MustCompile(`\w+`)
out := re.ReplaceAllStringFunc("hi there", strings.ToUpper)
fmt.Println(out)
Output
HI THERE

Split

Split — splitter as a regex

re := regexp.MustCompile(`\s*,\s*`)
fmt.Println(re.Split("a , b,c ,  d", -1))
Output
[a b c d]