Regular Expression Tester Guide: Test Regex Online, Choose the Right Flavour, and Move It into Code
A regex tester shows, as you type, what a pattern matches in sample text, which group captured what, and where it failed. It is the fastest way to write a regular expression. It is also where many regex bugs start, because the tester runs a different engine, different flags or a different string than your program does. Used with a little discipline, the result in the tester is the result in production.
Choose the flavour your code runs
There is no single regex language. JavaScript, Python, PCRE (PHP and many tools), Java, .NET and Go's RE2 share the basics and differ in features that matter.
feature JavaScript Python PCRE/PHP Java .NET Go (RE2)
named group (?<n>..) (?P<n>..) (?<n>..) (?<n>..) (?<n>..) (?P<n>..)*
lookbehind yes fixed width fixed width bounded any no
possessive a++ no 3.11+ yes yes no no
atomic (?>..) no 3.11+ yes yes yes no
backreferences \1 yes yes yes yes yes no
end of string $ (no m) \Z \z or $ + D \z \z \z
* Go 1.22+ also accepts (?<n>...); Python accepts only (?P<n>...)
Go's RE2 has no lookaround or backreferences at all, by design, because it guarantees linear-time matching. A pattern that works in a JavaScript tester may simply not compile in Go. If your tester has a flavour switch, set it before you start, not after the pattern is finished. The tester on this site has none: it runs your browser's JavaScript engine, so for a Python, PHP or Go pattern use it for the shared basics and confirm the rest in that language.
Match the flags too
Flags change results as much as the pattern does: g (all matches), i (ignore case), m (^ and $ per line), s (dot matches newline), u/v (Unicode), x (verbose, in PCRE and Python). Testers often enable g and m by default, because highlighting every match on every line looks helpful. A validation pattern that looks right with m on then accepts valid\nanything in code where the whole string is checked.
Set the tester's flags to exactly what your code uses, including none.
Build a test set, not a test string
One sample line proves little. Paste two lists: strings that must match and strings that must not. For an order ID pattern such as ^ORD-\d{6}$:
must match must NOT match
ORD-000001 ORD-00001 (too short)
ORD-999999 ORD-1234567 (too long)
ord-123456 (case)
ORD-123456\n (trailing newline)
xORD-123456 (prefix)
ORD-123456 (full-width digit: \d matches it in Python and .NET)
The negative list is where the value is. Include empty input, whitespace, the maximum length plus one, Unicode look-alikes and a valid value embedded in longer text. Once the pattern passes, copy both lists into a unit test so the next person who edits the regex cannot silently break it.
Read groups and test replacements
Testers list each match with its capture groups and their positions. Check that each group captured what you intended. An optional group that did not participate returns undefined in JavaScript, None in Python and an empty string in PHP, and code often handles only one of those.
Replacement syntax is different in every language, so test it in the tester's substitution mode with the right flavour selected:
JavaScript 'Doe, John'.replace(/(\w+), (\w+)/, '$2 $1') // 'John Doe'
Python re.sub(r'(\w+), (\w+)', r'\2 \1', 'Doe, John')
re.sub(r'(?P<last>\w+), (?P<first>\w+)', r'\g<first> \g<last>', s)
PHP preg_replace('/(\w+), (\w+)/', '$2 $1', 'Doe, John');
Java "Doe, John".replaceAll("(\\w+), (\\w+)", "$2 $1");
.NET Regex.Replace("Doe, John", @"(\w+), (\w+)", "$2 $1");
A literal $ in a JavaScript or Java replacement string must be written $$ and \$ respectively. Otherwise $1 in a price like "$10" is read as a group reference.
Moving the pattern into code: escaping
The tester shows the pattern as the regex engine sees it. Your source code wraps it in a string literal, which has its own escaping rules. This step breaks more patterns than anything else.
pattern in the tester: \d+\.\d{2}
JavaScript literal /\d+\.\d{2}/ as-is
JavaScript string new RegExp('\\d+\\.\\d{2}') every \ doubled
Python r'\d+\.\d{2}' raw string: as-is
Java "\\d+\\.\\d{2}" every \ doubled
C# @"\d+\.\d{2}" verbatim string: as-is
PHP '/\d+\.\d{2}/' delimiters; single quotes
In Java and in JavaScript's new RegExp(), forgetting to double a backslash turns \d into d or \. into .. The pattern still compiles and matches the wrong things. In Python, forgetting the r prefix mostly works by accident until \b becomes a backspace character. When a regex behaves differently in code than in the tester, print the pattern string at runtime and paste that into the tester.
Build patterns from user input only with escaping: re.escape() in Python, Pattern.quote() in Java, preg_quote() in PHP, Regex.Escape() in .NET and, in JavaScript, RegExp.escape() where available or a small escaping function.
Check performance before shipping
Many testers report the number of steps a match took, or time out on runaway patterns. Test your pattern against a long string that almost matches, such as 30 a characters followed by ! for a pattern with nested quantifiers. If the step count explodes, the pattern is vulnerable to catastrophic backtracking (ReDoS), and a single request can occupy a server core. Remove nested or overlapping quantifiers, anchor the pattern, and limit input length.
Sources and further reading
MDN's regular expressions guide (JavaScript), the Python re documentation, the PCRE2 pattern documentation, Java's java.util.regex.Pattern Javadoc, Microsoft's .NET regular expression language reference and the RE2 syntax page document the flavour differences above. The OWASP page on ReDoS describes catastrophic backtracking.
Frequently asked questions
How do I test a regular expression online?
Paste the pattern into a regex tester, select the flavour and flags your code uses, and paste sample text containing both strings that should match and strings that should not. Check the highlighted matches and the captured groups, then copy the test cases into a unit test.
Why does my regex work in the tester but not in my code?
Usually the flavour or flags differ, or the backslashes were not escaped for the string literal. Print the pattern at runtime, paste it into the tester with the same flavour and flags, and compare.
Which regex flavour should I choose?
The one your code runs: JavaScript for browsers and Node.js, Python for `re`, PCRE for PHP, Java for `java.util.regex`, .NET for C#, and RE2 for Go. Features such as lookbehind, named-group syntax and possessive quantifiers differ between them.
How do I test a Java regular expression?
Choose the Java flavour in the tester and test the pattern in its raw form. When you paste it into Java source, double every backslash, because Java string literals treat `\` as an escape character.
What is a regex checker?
Another name for a regex tester: a tool that checks a pattern against sample text and highlights the matches, groups and errors as you type.
How can I test a regex for performance problems?
Run it against long inputs that almost match and watch the step count or time in the tester. Exponential growth means catastrophic backtracking; simplify nested quantifiers and cap input length.