Regex Tester
Type a JavaScript regular expression and a test string and see every match highlighted, with its position and its numbered and named capture groups, as you type. The example below, (?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}) with the g flag, finds 3 matches; the first is “2024-03-15” (year = 2024, month = 03, day = 15), and the replacement $<day>/$<month>/$<year> turns the text into “Released 15/03/2024, patched 02/04/2024 and retired on 31/01/2025.”. Matching runs in a background thread with a 1-second limit, so a runaway pattern is stopped instead of freezing the page. Everything happens in your browser; your text is never uploaded.
Updated Runs in your browser: nothing you enter is uploadedHow this tool works
JavaScript (ECMAScript) syntax. Replace the example: type a pattern and a test string.
Stays in your browserMatched on this device and never uploaded or saved. Only the first 200,000 characters are searched, and matching is stopped after one second.
$1 numbered group, $<name> named group, $& the whole match, $$ a dollar sign.
Result
Released 15/03/2024, patched 02/04/2024 and retired on 31/01/2025.
Matches
3 matches
Released 2024-03-15, patched 2024-04-02 and retired on 2025-01-31.
Match 1 index 9, length 10
2024-03-15- Group 1 (year)
2024- Group 2 (month)
03- Group 3 (day)
15
Match 2 index 29, length 10
2024-04-02- Group 1 (year)
2024- Group 2 (month)
04- Group 3 (day)
02
Match 3 index 55, length 10
2025-01-31- Group 1 (year)
2025- Group 2 (month)
01- Group 3 (day)
31
What each flag does
| Flag | Name | Effect | Example | Without the flag | With the flag |
|---|---|---|---|---|---|
| g | global | Find every match, not just the first. | /\d/ on “a1b2c3” | “1” | “1”, “2”, “3” |
| i | ignore case | Treat upper and lower case letters as equal. | /cat/g on “Cat cAt” | No match | “Cat”, “cAt” |
| m | multiline | ^ and $ match at every line break, not only at the ends of the text. | /^\w+/g on “one⏎two” | “one” | “one”, “two” |
| s | dotAll | . also matches line breaks. | /a.b/g on “a⏎b” | No match | “a b” |
| u | unicode | Match whole code points; enables \p{…} property escapes and stricter syntax. | /^.$/g on “😀” | No match | “😀” |
| y | sticky | Only match starting exactly where the search begins. | /b/g on “ab” | “b” | No match |
| v | unicodeSets | Like u, plus set operations and string properties inside [ ]. Cannot be combined with u. | /[\p{L}--[a-z]]+/gu on “abcÄÖ” | Syntax error: Invalid character class | “ÄÖ” |
| d | indices | Also report where each capture group starts and ends. | Shown under each group as “index start to end” | No group positions | Group positions listed |
Common pieces of syntax
| Syntax | Meaning | Example | Matches |
|---|---|---|---|
| . | Any character except a line break (with s: any character) | /a.c/g on “abc a-c” | “abc”, “a-c” |
| \d \w \s | A digit, a word character (letter, digit, underscore), a whitespace character | /\w\d/g on “a1 b2” | “a1”, “b2” |
| [abc] [^abc] [a-z] | One of the listed characters, anything but those, or a range | /[^aeiou ]+/g on “regex tester” | “r”, “g”, “x”, “t”, “st”, “r” |
| * + ? {n,m} | Zero or more, one or more, zero or one, between n and m repeats (greedy) | /o{2,3}/g on “o oo ooo oooo” | “oo”, “ooo”, “ooo” |
| *? +? ?? | The same repeats, lazy: as few characters as possible | /<.+?>/g on “<b>bold</b>” | “<b>”, “</b>” |
| ^ $ \b | Start of the text (or line with m), end of the text (or line), a word boundary | /\bcat\b/g on “cat concat cat.” | “cat”, “cat” |
| ( ) (?: ) | A capture group, and a group that does not capture | /(ab)+/g on “ababab ab” | “ababab”, “ab” |
| (?<name> ) | A named capture group, read back as $<name> or in match.groups | /(?<h>\d+):(?<m>\d+)/g on “at 09:30” | “09:30” |
| a|b | Either alternative | /cat|dog/g on “hotdog catfish” | “dog”, “cat” |
| (?= ) (?! ) | Lookahead: followed by, or not followed by | /\w+(?=;)/g on “a; b c;” | “a”, “c” |
| (?<= ) (?<! ) | Lookbehind: preceded by, or not preceded by | /(?<=\$)\d+/g on “cost $40 or 50” | “40” |
| \1 \k<name> | The text a numbered or named group matched earlier | /(\w)\1/g on “hello book” | “ll”, “oo” |
| \p{L} | A Unicode letter (needs the u or v flag) | /\p{L}+/gu on “naïve 123” | “naïve” |
Replacement patterns
| Token | Inserts | Example | Result |
|---|---|---|---|
| $1, $2 … $99 | The text of that numbered capture group (empty if it did not take part) | $2, $1 on “Ada Lovelace” | “Lovelace, Ada” |
| $<name> | The text of a named group (only when the pattern has named groups; otherwise it stays as typed) | $<last>, $<first> on “Ada Lovelace” | “Lovelace, Ada” |
| $& | The whole matched text | [$&] on “Ada Lovelace” | “[Ada Lovelace]” |
| $` | The part of the text before the match | <$`> on “Ada Lovelace” | “<>” |
| $' | The part of the text after the match | <$'> on “Ada Lovelace” | “<>” |
| $$ | A literal dollar sign | $$$1 on “Ada Lovelace” | “$Ada” |
| $0, $3 (no such group) | Left as typed, because there is no group with that number | $0|$3 on “Ada Lovelace” | “$0|$3” |
Limits and safety
| Limit | Value | What happens beyond it |
|---|---|---|
| Time per run | 1 second | The matching thread is stopped and replaced, and the page says the match took too long (possible catastrophic backtracking). |
| Matches shown | 1,000 | Matching stops there and the page says more were found. |
| Test string | 200,000 characters | Only the first part is searched, and the page says so. |
| Long match or group text | 300 characters | The list shows the start followed by “…”; the highlight and replacement use the full text. |
How to test a regular expression
- Enter the pattern. Type the expression, without the surrounding slashes, in “Regular expression”. A syntax error is explained under the results as you type.
- Choose the flags. Tick g to find every match, i to ignore case, m, s, u, v, y or d as needed. They are the same letters you would write after the closing slash.
- Paste a test string. Put the text to search in “Test string”. Matches are highlighted in the copy below it and listed with their position.
- Read the matches and groups. Each match shows its index and length, then every capture group, numbered and named, or a note when a group did not take part.
- Try a replacement. Tick “Replace mode” and type a replacement such as $2 $1 or $<name> to see the replaced text, then copy it.
Frequently asked questions
- Which regular expression flavor does this use?
- JavaScript’s own, ECMAScript, as implemented by your browser: the page builds a real RegExp object from your pattern and flags. That means lookbehind, named groups, Unicode property escapes and the v flag work if your browser supports them, and the syntax of other flavors (PCRE, Python, .NET) is not accepted where it differs, for example possessive quantifiers, atomic groups and inline modifiers in older browsers.
- What is catastrophic backtracking, and why does the page say a match took too long?
- Some patterns, such as (a+)+$ on a long run of a’s followed by another letter, make the engine try an exponential number of ways to match before giving up. In a normal page that freezes the tab. Here the match runs in a Web Worker; after 1 second it is stopped, a fresh worker is started, and you get the message “took too long — possible catastrophic backtracking”. Rewrite the pattern so that repeats cannot overlap, for example a+$ instead of (a+)+$.
- Is my text uploaded?
- No. The pattern and the text are matched in your browser, in a background thread of this page, and are never sent or stored. If you allow analytics, the site records only that the tool was used, never what you typed.
- How do I use capture groups in a replacement?
- Put $1, $2 and so on for numbered groups, or $<name> for a named group such as (?<year>\d{4}), in the replacement. $& inserts the whole match, $` and $' insert the text before and after it, and $$ inserts a dollar sign. These are the rules of JavaScript’s String.prototype.replace.
- Why does my pattern only find one match?
- Without the g flag a regular expression stops at the first match. Tick g to find all of them. With the y flag, matching must also begin exactly where the search starts, so y alone finds a match only at the very beginning of the text, and y together with g finds a run of back-to-back matches.
- What does a match with an empty text mean?
- A pattern like a* or ^ can match zero characters. Those matches are real: the page lists them as empty matches, draws a thin marker where they occur, and, like JavaScript, moves one character on before looking for the next match so it cannot loop forever.
- Why is the u or v flag needed for \p{L} or emoji?
- Without u or v a regular expression reads text as 16-bit units, so a character outside the Basic Multilingual Plane, such as an emoji, counts as two. With u or v it reads whole code points and unlocks \p{…} Unicode property escapes. The v flag adds set operations like [\p{L}--[a-z]] and cannot be combined with u; choosing one clears the other.
- Why do I get a syntax error message?
- The browser rejected the pattern when building the RegExp, and the page shows its reason: for example an unterminated group, a nothing-to-repeat quantifier, an invalid escape under the u flag, or a lookbehind your browser does not support. Messages come from your browser, so their wording can differ between Chrome, Firefox and Safari.
- Is anything cut off for large inputs?
- Yes, to keep the page quick: only the first 200,000 characters of the test string are searched, at most 1,000 matches are listed, and long match or group values are shortened to 300 characters in the list. The page tells you whenever one of these limits applies.
How it works
The pattern and the flags you tick are passed to the browser’s own RegExp constructor, so the result is exactly what that browser’s JavaScript engine would produce; this page adds no matching engine of its own. With the g flag the page calls exec repeatedly and, after an empty match, advances by one code unit (one code point under u or v) as String.prototype.matchAll does; without g it stops after the first match. Group names are read from the pattern text in the order of their opening parentheses, so numbered and named groups can be shown together. Replacement uses the specification’s GetSubstitution rules for $$, $&, $`, $', $n, $nn and $<name>. All of this runs in a dedicated Web Worker. If a run is still going after 1 second, or you change the input while it runs, the worker is terminated and a new one is created, which is the only reliable way to stop a regular expression that is backtracking without end. Highlighting is built from text nodes and mark elements, never from HTML, so pasted markup is shown as text and cannot run.
Sources
- ECMA-262: RegExp (Regular Expression) Objects
- ECMA-262: Pattern grammar and semantics
- ECMA-262: GetSubstitution (replacement patterns)
- MDN: RegExp
- MDN: Regular expressions guide
- MDN: String.prototype.replace (specifying a string as the replacement)
- MDN: Using Web Workers
- OWASP: Regular expression Denial of Service (ReDoS)
More free tools
- Text CompareCompare two texts and see what changed, line by line with changed words highlighted. Ignore case or spacing, copy a unified diff. Stays in your browser.
- Remove Duplicate LinesRemove duplicate lines from a list, keep the first or last copy, and sort A to Z, naturally or at random. Works in any language and stays in your browser.
- URL Encode & DecodePercent-encode or decode URLs and query strings with correct UTF-8, split a URL into parts and parameters, and catch double-encoding. Runs in your browser.
- Word CounterCount words, characters, sentences and reading time, and check your text against X, LinkedIn, Instagram, SMS and meta description limits.
- Case ConverterConvert text to UPPERCASE, lowercase, Title Case, Sentence case, camelCase, PascalCase, snake_case, kebab-case or CONSTANT_CASE. Stays in your browser.
- Lorem Ipsum GeneratorGenerate lorem ipsum by paragraphs, sentences, words or an exact character count, as plain text, HTML or Markdown. Built from the classic Latin passage.