How I test a regex before putting it into code
· 4 min read
Regex is powerful, but it is also easy to get almost right. “Almost right” is the problem. A regex can match too much, too little, or the right thing in your test but the wrong thing in production.
That is why I test patterns with the Regex Tester before I put them into code. If I need replacement, I use the Regex Replace Tester too.
The simple idea
A regex is a pattern for matching text.
Example:
error
This matches the word error.
A slightly more flexible pattern:
errors?
This matches:
error
errors
because s? means “the s is optional”.
Step 1: start with real sample text
Do not test a regex only on perfect input. Paste realistic examples into the tester.
For example, if I am matching log lines, I paste several real-looking lines:
2026-09-27 10:00:01 INFO server started
2026-09-27 10:00:03 ERROR database connection failed
2026-09-27 10:00:04 WARN retrying connection
Then I build the pattern against that sample.
Good sample text should include:
- lines that should match;
- lines that should not match;
- edge cases;
- messy input if real input is messy.
Step 2: start simple
I do not start with a clever regex. I start with the smallest useful pattern.
ERROR
Then I add detail:
^\d{4}-\d{2}-\d{2} .* ERROR .*$
Plain meaning:
- start at the beginning of the line;
- match a date like
2026-09-27; - match anything after it;
- require
ERROR; - match the rest of the line.
Building in steps makes it easier to see where the pattern breaks.
Step 3: understand anchors
Anchors do not match characters. They match positions.
Common anchors:
^
means start of line or string.
$
means end of line or string.
Example:
^ERROR
matches lines that start with ERROR.
It does not match:
2026-09-27 ERROR failed
because ERROR is not at the start.
Step 4: use character classes carefully
A character class matches one character from a set.
[abc]
matches a, b, or c.
Common shortcuts:
\d
matches a digit.
\w
matches a word character.
\s
matches whitespace.
A date pattern might use:
\d{4}-\d{2}-\d{2}
Plain meaning:
four digits, dash, two digits, dash, two digits.
Step 5: watch greedy matching
This pattern is greedy:
<.*>
Given:
<b>one</b><i>two</i>
it may match from the first < to the last >:
<b>one</b><i>two</i>
not just:
<b>
A less greedy version uses ?:
<.*?>
Regex and HTML are a dangerous mix for real parsing, but this example shows why greediness matters.
Step 6: use capture groups intentionally
Parentheses capture parts of a match.
Example:
user_id=(\d+)
Given:
user_id=123
The whole match is:
user_id=123
The captured group is:
123
Capture groups are useful when code needs only part of the match.
Step 7: test replacement separately
Replacement has its own risks. A pattern can match correctly but replace badly.
Suppose I want to turn:
Doe, Jane
into:
Jane Doe
Pattern:
(\w+),\s*(\w+)
Replacement:
$2 $1
Use Regex Replace Tester to preview this before running it across real text.
Step 8: check flags
Flags change regex behaviour.
Common flags:
i: case-insensitive;g: global, match more than once;m: multiline anchors;s: dot also matches newlines, depending on the engine.
The same pattern can behave differently with different flags. Always test with the same flags your code will use.
Step 9: know your regex engine
JavaScript, Python, PostgreSQL, nginx, and grep do not all support exactly the same regex features.
A pattern that works in one place may fail in another.
Before using advanced features, check whether your target environment supports them. For simple patterns, this rarely matters. For lookbehind, named groups, or Unicode features, it can matter a lot.
My regex checklist
Before using a regex in code, I check:
- Did I test it with realistic sample text?
- Did I include examples that should not match?
- Is the pattern too broad?
- Do anchors behave the way I expect?
- Are greedy parts safe?
- Are capture groups intentional?
- Are flags correct?
- If replacing text, did I preview the replacement?
- Does my target environment support this regex syntax?
Regex is useful when the pattern is clear. The tester helps make that clarity visible before the pattern touches real data.
Comments
Comments are welcome — please read the comment policy first. Powered by giscus and GitHub Discussions.