The match table shows up to 1,000 matches. Replacement output includes every match and is limited to 2 million characters. Runs that exceed the time or output limit report an error.
RE2 syntax compared with other engines
| Feature | Go (RE2) | Python, JavaScript, PCRE |
|---|---|---|
Lookahead / lookbehind (?=…) (?<=…) | No | Yes |
Backreferences \1 | No | Yes |
Possessive / atomic a++ (?>…) | No | PCRE, Python 3.11+ |
| Named groups | (?P<name>…) or (?<name>…) | Python needs (?P<name>…) |
\d, \w, \b | ASCII only | Unicode in Python |
| Unicode classes | \pL, \p{Greek} | \p{L} in JS (u flag); not in Python re |
| POSIX classes | [[:alpha:]] | PCRE only |
| Ungreedy flag | (?U) | PCRE only |
| Literal text | \Q…\E | PCRE, Java |
| Worst-case time | Linear | Exponential (backtracking) |
Using the pattern in Go
// Compile once, at package level; MustCompile panics on a bad pattern.
var email = regexp.MustCompile(`(?P<user>[\w.+-]+)@(?P<domain>[\w-]+(?:\.[\w-]+)+)`)
func main() {
text := "Contact ada@example.com or grace@navy.mil"
fmt.Println(email.MatchString(text)) // true
fmt.Println(email.FindAllString(text, -1)) // [ada@example.com grace@navy.mil]
for _, m := range email.FindAllStringSubmatch(text, -1) {
fmt.Println(m[email.SubexpIndex("domain")])
}
fmt.Println(email.ReplaceAllString(text, "${user} at ${domain}"))
}
Write patterns as raw string literals in backticks so backslashes don’t need doubling. For untrusted patterns, use
regexp.Compile and handle the error instead of MustCompile. Porting a pattern from Python?
Test it in the Python regex tester first, then here.
Frequently asked questions
Why doesn’t Go support lookahead, lookbehind or backreferences?
Go’s regexp package implements RE2 syntax, which guarantees matching in time linear in the input. Lookarounds and backreferences can require exponential backtracking, so RE2 leaves them out. The upside: a Go regex can never hang on malicious input (no ReDoS). Workarounds: match more and check the rest in code, use two simpler regexes, or use a third-party engine like github.com/dlclark/regexp2.
Does this run Go’s regexp package?
Your pattern is translated into an equivalent JavaScript regex and run in your browser. The translation follows Go’s rules: ASCII-only \d, \w, \s and \b, $ that matches only at the end of the text, (?U) ungreedy mode, flags like (?i) that apply to the rest of the group, POSIX classes, \Q…\E, and FindAll skipping empty matches that touch the previous match. Unsupported syntax gives the same error message as regexp.Compile. We check it against Go 1.26 on a test suite.
Why are the positions in bytes?
Go strings are UTF-8 byte sequences, and FindStringIndex and FindAllStringSubmatchIndex return byte offsets. A character like é takes 2 bytes and an emoji 4, so positions after them differ from character counts. The table shows byte offsets so you can use them directly with text[start:end].
What is the difference between FindString, FindAllString and FindStringSubmatch?
FindString returns the first match. FindAllString(s, -1) returns all matches (pass n ≥ 0 to limit them). The Submatch variants also return the groups: element 0 is the whole match, then one element per group. Index variants return positions instead of text. MatchString just reports whether there is a match.
How do I use named groups in Go?
Write (?P<name>re), or (?<name>re) since Go 1.22. Get the index with re.SubexpIndex("name") and read match[index], or refer to it as ${name} in ReplaceAllString. Use ${name} rather than $name when text follows, because $name1 means a group called “name1”.