Loading Regex Tester…
Written without the surrounding slashes. The pattern is passed to the RegExp constructor, never evaluated as code.
g Keeps searching after the first hit instead of stopping there. Without it you get one match, however many exist.2024-01-14at index 8202401142024-02-03at index 30202402032024-02-29at index 50202402292024-03-11at index 7720240311A pattern either agrees with your text or it does not, and when the answer is “not” the useful question is which part disagreed. This tester lists every match with the character offset it starts at, so a pattern finding three of the four dates in a log line shows you which three — and the gap tells you what your character class forgot. It matches as you type, so the list is never a stale answer to an older pattern.
Each flag is listed with what it changes rather than as a bare checkbox, because two of them are routinely confused. The m flag retargets ^ and $ at the start and end of every line; s is the one that lets a dot cross a newline. So /^\d+$/m against three lines of numbers matches each line separately, and adding s changes nothing — while /a.b/s will happily match an “a”, a line break and a “b”.
The rest earn their place too. Without g you get one match however many exist. The u flag treats the pattern as code points, so \u{1F600} is legal and an emoji counts as one unit rather than two; v is its stricter successor and cannot be combined with it, so ticking one here unticks the other.
Capture groups are numbered by the position of their opening parenthesis, counting from the left, which is why adding one at the front silently renumbers everything after it. Naming them with (?<year>…) is the fix, and both the number and the name are shown here so a rewritten pattern can be checked against the code that consumes it.
A group can also match nothing at all, which is different from matching an empty string. Run /(a)|(b)/ against the text “b” and group 1 is reported here as not having participated, while group 2 holds “b”. In JavaScript that first value is undefined, and code that assumes a string is what crashes. Where a group exists only to carry a quantifier, (?:…) keeps it out of the numbering.
Some patterns are not slow, they are effectively infinite. Given /(a+)+$/ and thirty a characters followed by a b, the engine must try every way of dividing those thirty characters between the inner and outer repetition before concluding there is no match — roughly a billion attempts, and each extra a doubles it. That is catastrophic backtracking, and as a denial-of-service vector it has its own name, ReDoS.
JavaScript cannot interrupt a running regex: there is no timeout argument and no way to cancel one, so once exec starts the only thing that ends it is the answer. This tool therefore checks the pattern first, and a repetition wrapped around a group that itself repeats or alternates is refused behind an explicit “run it anyway”. The check is deliberately cautious and will sometimes hold back a pattern that would have been fine — one extra click, against a dead tab and lost text.
Your pattern is passed to new RegExp inside a try/catch. That matters because the obvious shortcut — evaluating /pattern/flags as a literal — would run whatever was pasted in as JavaScript. An unbalanced bracket or a bad quantifier instead comes back as the engine’s own SyntaxError, reported in place of the results.
The loop around it is bounded too: the first 20,000 characters are searched, at most 500 matches are listed, and a run over its time budget admits the list is incomplete. A zero-length match advances the cursor by one rather than looping forever, which is what /a*/g against “bbb” would otherwise do. Everything runs in your browser, so the text being tested never leaves the machine.
Because they are different flavours. This tester uses the JavaScript engine, while PCRE, Python and Go differ in the details: recursion, possessive quantifiers and \K exist in some and not others. Test against the engine that will actually run the pattern.
It makes the regex object stateful. A global regex remembers a lastIndex between calls, so calling test() twice on the same string can return true and then false — a classic source of matches that vanish for no visible reason.
Because that branch never ran — usually an alternation where the other side matched, or an optional group that was skipped. JavaScript gives you undefined there rather than an empty string, which is worth handling before it reaches a string method.
Make the repetition unambiguous, so there is only one way to divide the input. Replacing (\w+\s?)+ with \w+(?:\s\w+)* is the usual shape of the fix: the second form can match the same text in exactly one way.