fmt, io, os, bufio, encoding/json, net/http, time, slog, regexp, flag, embed.
regexp — Regular Expressions
Go's regexp package uses the RE2 engine — the same one in Google Search. RE2
guarantees linear-time matching, which means no pathological backtracking,
but also means no backreferences (no \1). For 99% of validation, parsing,
and extraction work, RE2 is what you want.
Compile once, match many
re := regexp.MustCompile(`^\d{4}-\d{2}-\d{2}$`)
re.MatchString("2026-05-20") // true
re.MatchString("not a date") // false
Use MustCompile for constant patterns — it panics at startup if the regex
is malformed, which beats a runtime error a week into production. For
user-supplied patterns, use regexp.Compile(pattern) and handle the error.
Find, FindAll, and submatches
Find→ first match.FindAll→ every non-overlapping match (-1means no limit).Submatch→ also returns capture groups. Index 0 is the whole match, 1 is the first group, etc.
Named groups
Named captures are easier to read at a callsite:
re := regexp.MustCompile(`(?P<key>\w+)=(?P<value>\d+)`)
m := re.FindStringSubmatch("x=42")
i := re.SubexpIndex("value")
fmt.Println(m[i]) // 42
Replace
re := regexp.MustCompile(`\s+`)
re.ReplaceAllString("hello there world", " ")
// "hello there world"
Use ${1} (or ${name}) inside the replacement to splice in captures:
re := regexp.MustCompile(`(\d+)`)
re.ReplaceAllString("v123 r456", "<$1>")
// "v<123> r<456>"
Raw strings save your sanity
Backslashes are common in regexes. Use raw strings (backticks) so you don't double-escape:
re := regexp.MustCompile(`\d+\.\d+`) // not "\\d+\\.\\d+"
When NOT to use regexp
- Email validation → use
net/mail.ParseAddress. - URL parsing →
net/url.Parse. - HTML/XML →
golang.org/x/net/html, never regex. - Number parsing →
strconv.ParseInt/ParseFloat.
Regex is great for ad-hoc structured text. It's a footgun for anything with a real grammar.