Regex Debugger — Examples
Walkthroughs with the Regex Debugger: match emails, read groups, test flags and lookaround, replace, split, and generate code for PHP and Python.
Back to the overview: Regex Debugger · Open the tool: www.jpkc.com/tools/regex/
The manual describes every field and flag. This page complements it with concrete walkthroughs: real patterns that run in the JavaScript engine, each with matching test text and an explanation of what you'll see in the match display. You can type all examples directly — pattern into the Pattern field, text into the Test String field, flags as noted, and replacements into the Replacement field on the Replace tab.
Example 1: Match email addresses
The classic — find all email addresses in a block of text. Start with the obvious pattern:
- Pattern:
[\w.+-]+@[\w-]+\.[\w.-]+ - Flags:
g - Test String:
Write to info@example.com or to support@mail.example.org.
Spam to: nope@.com (invalid).Matches lists two hits, each with pos X–Y, and highlights them in the text. nope@.com isn't matched because at least one word character has to follow the @. But look closely at the second hit: support@mail.example.org. — the full stop at the end of the sentence is included, because [\w.-]+ happily eats dots too. That's exactly what the debugger is for: you see at once where your pattern is too lax.
The fix is in the Library under "E-mail address (pragmatic)": [\w.+-]+@[\w-]+(?:\.[\w-]+)+. Here every dot in the domain must be followed by at least one word character — the full stop drops out, and the second hit is a clean support@mail.example.org. Toggle g off for a moment and watch the list shrink to only the first match.
Example 2: Read capture groups — break apart a date
Capture groups grab parts of a match separately. Here you break a date into day, month, and year.
- Pattern:
(\d{2})\.(\d{2})\.(\d{4}) - Flags:
g - Test String:
Meeting on 19.06.2026, deadline 30.06.2026.Each match shows the numbered groups below the match value: group 1 the day, group 2 the month, group 3 the year — each number in the color used to underline that group in the test string. That's how you check whether your parentheses grab the right pieces before you process them in code via match[1], match[2], and so on. Note: the dots in the pattern are escaped as \. — a bare . would match any character.
Example 3: Named capture groups
Instead of remembering group 1/2/3, give the groups names.
- Pattern:
(?<day>\d{2})\.(?<month>\d{2})\.(?<year>\d{4}) - Flags:
g - Test String:
Meeting on 19.06.2026.In Matches, each group number is now followed by its name — <day>, <month>, and <year> — and then the value. In code you later read them via match.groups.day — more readable and more robust than relying on parenthesis order. The tool's starting example, (?<word>\w+), shows the same principle on individual words.
Example 4: Try the flags — i, m, and s
The same input, three flags, three results. Take this multi-line text:
Error: file not found
error: access denied
OK: all goodi(case insensitive). Patternerror, onlyg: matches just the lowercase line. Addi— now both "error" lines match, regardless of case.m(multiline). Pattern^error, flagsgandi. Withoutm, the anchor^only matches at the very start of the string — you get only the "Error" of the first line, and the second line isn't caught. Withm,^matches every line start, and the "error" line in the middle is matched as well.s(dotall). Patternfound.*access, onlyg. Withouts,.matches no newline, so the match never forms. Withs,.may skip over newlines — the expression now spans the line break. The Explain tab spells out the difference too: withouts, the dot reads "any character except line breaks"; withs, "any character, including newlines".
This gives you a feel for the fact that the flags aren't cosmetic; they change the semantics of the pattern.
Example 5: Lookaround — check context without capturing it
Lookahead and lookbehind check the surroundings of a match without making them part of the match itself. JavaScript handles both directions.
- Pattern (lookbehind):
(?<=\$\s?)\d+(?:\.\d{2})? - Flags:
g - Test String:
Price: $ 19.99 — down from $ 29.99. Item number 12345.The positive lookbehind (?<=\$\s?) requires a dollar sign (optionally followed by a space) before the number — but only the number is matched. So you find amounts without picking up the 12345 that has no dollar prefix. In the match list you'll see only 19.99 and 29.99, not the $.
Example 6: Invalid pattern and zero-length matches
Two instructive edge cases.
- Invalid pattern: Type
(unbalancedinto the Pattern field. NoRegExpcan be built — the match list stays empty, the engine's original error message appears below the flags, and the counter reads "Error". Close the parenthesis ((unbalanced)) and the error disappears immediately. - Zero-length match: Pattern
\b, flagsg, any text. A word boundary has no width — it matches "between" characters. The tool counts these matches correctly (each as "(empty)" withpos X–X, start equal to end) without getting stuck in the infinite loop a global zero-length match would otherwise trigger.
Example 7: Catastrophic backtracking — the timeout
What happens when a pattern tries an exponential number of paths? This experiment shows it safely:
- Pattern:
(a+)+$ - Flags:
g - Test String: thirty
acharacters followed by an exclamation mark:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!Because the ! sits at the end, $ can never match — so the engine works through every way of splitting the run of a between the inner and the outer repetition. After 1.5 seconds the tool gives up: the counter shows "Timeout", and the status line names nested quantifiers as the likely cause. The page stays usable throughout. Replace the pattern with a+$ and the result — no match — appears instantly. How to defuse patterns like this is covered in the tips.
Example 8: Search and replace — change the date format
The Replace tab shows you the result of String.replace() before you carry it over into your code. The quickest route is the Library: pick "ISO date (named groups)". The tool sets:
- Pattern:
(?<year>\d{4})-(?<month>0[1-9]|1[0-2])-(?<day>0[1-9]|[12]\d|3[01]) - Flags:
g - Test String:
Released 2026-10-15, updated 2026-12-31. Invalid: 2026-13-01- Replacement:
$<day>.$<month>.$<year>
Switch to the Replace tab. The result reads:
Released 15.10.2026, updated 31.12.2026. Invalid: 2026-13-01The two valid dates are now in the day.month.year format common in Germany, while 2026-13-01 stays as it is, because month 13 doesn't fit the month group. Above the result it says "All matches replaced.". Toggle g off — now it reads "Without flag g only the first match is replaced.", and only the first date changes. Copy result takes the rewritten text with you. You can insert the replacement tokens $1, $<name>, $&, and friends with a click from the cheat sheet's Replacement section.
Example 9: Break text apart with Split
The Split tab shows what text.split(regex) returns — including the quirk that capture groups end up in the result.
- Pattern:
\s*[,;]\s* - Flags:
g - Test String:
apple, pear;cherry ,plumThe list shows four entries, numbered from 0: apple, pear, cherry, plum — the spaces around the separators are gone because the pattern consumes them. Now wrap the separators in a group: \s*([,;])\s*. The list grows to seven entries, because every captured separator appears between the parts: apple, ,, pear, ;, cherry, ,, plum. If you need grouping without the group showing up in the split, use a non-capturing group (?:…).
Example 10: Explain the pattern and export it to PHP or Python
Take the date pattern from example 3 and enter a replacement on the Replace tab that turns the date into ISO format:
- Pattern:
(?<day>\d{2})\.(?<month>\d{2})\.(?<year>\d{4}) - Flags:
g - Replacement:
$<year>-$<month>-$<day>
On the Explain tab you read the pattern piece by piece: "Start of capturing group 1 "day"", indented below it \d as "a digit (0–9)" and {2} as "… repeated exactly 2 times — as many as possible (greedy)", then "End of group 1 "day"", and so on.
On the Code tab you pick the target language under Language. For PHP (PCRE) the tool generates, among other things:
$pattern = '/(?<day>\\d{2})\\.(?<month>\\d{2})\\.(?<year>\\d{4})/';
// …
$result = preg_replace($pattern, '${3}-${2}-${1}', $text);Since preg_replace() has no named references, the tool translated $<year> and the others into group numbers — a yellow note above the code tells you so. For Python (re) it becomes:
pattern = re.compile(r'(?P<day>\d{2})\.(?P<month>\d{2})\.(?P<year>\d{4})')
# …
result = pattern.sub(r'\g<year>-\g<month>-\g<day>', text)Here the notes point out that the named groups were rewritten into Python's (?P<name>…) syntax and that in Python 3 \d also matches non-ASCII digits (remedy: re.ASCII). Copy code takes the result with you.
Going deeper: the overview for the big picture, the manual for every feature in detail, and the tips & tricks for pitfalls and engine quirks. You can try all of it directly in the tool.