Regex Tester
Live match highlighting, a match table and capture groups, as you type.
A regular expression is easy to write and hard to be sure about. It looks correct, matches the three examples you had in mind, and then quietly fails on the fourth. Testing against real sample text is the only reliable check, so this tester highlights every match as you type, lists them with their positions, and shows what each capture group actually captured.
| # | Match | Index | Groups |
|---|
How it works
Write your pattern
Enter it without the surrounding slashes; the flags sit beside them.
Toggle the flags
Global, case-insensitive, multiline, dot-all and unicode.
Check the matches
Highlighted in place, and listed below with index and captures.
The flags change more than they appear to
Without g a pattern stops at the first match, which is the right behaviour for validation and the wrong one for extraction. With it, the expression keeps a position between calls — the source of a classic bug where reusing one global regex object across several strings starts each search partway through the next.
The m flag redefines ^ and $ to mean the start and end of each line rather than of the whole string, which is what you want when the test string is a log file and not what you want when validating a single field. Without it, a pattern anchored with ^ and $ checks the entire input, newlines included — the reason a validation regex can accept a value with a newline smuggled onto the end.
The s flag makes . match line breaks as well; by default it matches anything except them. And u switches on proper Unicode handling, which is what makes \p{L} and code point escapes work and what stops an emoji being treated as two separate characters.
Greedy quantifiers, and the pattern that hangs the page
Quantifiers are greedy: .* takes as much as it can and gives back only when forced. Applied to <b>one</b> and <b>two</b>, the pattern <b>.*</b> matches the whole line rather than the first tag. Adding a question mark makes the quantifier lazy — .*? takes as little as possible — which is usually what was meant.
Greed also has a performance edge. Nested quantifiers over overlapping character sets, the classic being (a+)+b, force the engine to try an exponential number of ways to split the input before concluding there is no match. On a few dozen characters that can take longer than the age of the universe, and because JavaScript regular expressions run on the main thread, the tab simply stops responding. The condition has a name — catastrophic backtracking — and it is a real denial-of-service class in server-side code.
Two habits avoid nearly all of it. Prefer a negated character class to a dot when you know what must not appear: [^<]* instead of .*? when scanning up to a tag. And avoid quantifying a group that already contains a quantifier over the same characters. This tester runs against whatever you paste, so a pathological pattern will freeze the page here too — reload it and simplify.