DevToolsmith

Go Regex Tester

Test regular expressions for Go’s regexp package (RE2 syntax). See exactly what Go would match, with byte positions, groups and ReplaceAllString output, and get Go’s own error message for unsupported syntax like lookarounds and backreferences.

Runs 100% in your browser — nothing is uploaded

``
Flags

Use it in code

Go
re := regexp.MustCompile(`(?P<user>[\w.+-]+)@(?P<domain>[\w-]+(?:\.[\w-]+)+)`)

matches := re.FindAllStringSubmatch(text, -1)
for _, m := range matches {
	fmt.Println(m[0], m[1:])
}

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

FeatureGo (RE2)Python, JavaScript, PCRE
Lookahead / lookbehind (?=…) (?<=…)NoYes
Backreferences \1NoYes
Possessive / atomic a++ (?>…)NoPCRE, Python 3.11+
Named groups(?P<name>…) or (?<name>…)Python needs (?P<name>…)
\d, \w, \bASCII onlyUnicode 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…\EPCRE, Java
Worst-case timeLinearExponential (backtracking)

Using the pattern in Go

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”.