Regex Tester

Regex Tester

Test and debug regular expressions with real-time matching. Regex pattern builder with explanation. Free online regex tester for JavaScript, Python, PHP

Most regex problems are not "does this match" — they are "why does this match something I did not expect". This tester runs your pattern against many test strings in parallel, highlights every capture group, and shows the resulting JavaScript flag string. It uses the V8 RegExp engine that ships with your browser, so behavior here matches what you will get in production Node.js or front-end code.

What the engine actually is

The tester uses the native JavaScript RegExp object via new RegExp(pattern, flags). That means you are testing against the ECMAScript regex dialect specified in Annex B of the language standard — backtracking NFA, no atomic groups, no possessive quantifiers, no recursion. Patterns that work here will also work in Node 18+, Deno, Bun, and any modern browser.

If your target runtime is PCRE (PHP preg_*, nginx, many Linux utilities) or RE2 (Go, Cloudflare Workers, BigQuery), behavior diverges in edge cases: lookbehind support, possessive quantifiers, and catastrophic-backtracking protection differ. Test on the actual engine before shipping production patterns.

Working example: validating IPv4 with bounds

A surprisingly common bug is using \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} and calling it an IPv4 validator. That matches 999.999.999.999. The correct bounded version:

^(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)){3}$

Input

192.168.1.1
255.255.255.255
256.1.1.1
10.0.0.0
01.02.03.04

Output

✓ 192.168.1.1
✓ 255.255.255.255
✗ 256.1.1.1
✓ 10.0.0.0
✗ 01.02.03.04

Each octet alternation expresses 0–255 explicitly. Leading zeros are rejected because [1-9]?\d does not allow 0\d.

Flags that change semantics, not just convenience

  • g — without it, .exec() and .test() return at most one match, and replace() only replaces the first occurrence. Almost every multi-match bug starts here.
  • i — case-insensitive. Combine with \p{L} and the u flag for proper Unicode case folding (e.g. ß ↔ SS).
  • m — changes ^ and $ to match line boundaries inside the string. Does not enable . to cross lines; that is the s flag.
  • s — "dotall". Lets . match \n. Required for matching across multi-line YAML or JSON values.
  • u — Unicode mode. Enables \p{} property escapes, surrogate-pair-aware character classes, and stricter escape validation. Use this whenever your input may contain emoji or non-Latin scripts.
  • y — sticky. Anchors matching to lastIndex without requiring ^. Useful for tokenizers, rarely useful otherwise.

When to reach for this tool

  • You have a regex that works on three test cases and you need to confirm it fails on twenty edge cases before merging.
  • You inherited a pattern with five nested groups and need to see exactly what each group captures on real data.
  • You are migrating patterns from PCRE/RE2 and need to verify each one still works in V8 — paste both the pattern and a representative corpus.
  • You are writing extraction logic and want to compare 4-5 candidate patterns side-by-side on the same input.

What this tool will not do

  • It will not protect you from catastrophic backtracking. A pattern like (a+)+$ on "aaaaaaaaaaaaaaaaaaaaab" can freeze your tab. The engine is the same one your production code uses — if it hangs here, it will hang there.
  • It will not translate between dialects. PCRE recursion (?R), .NET balanced groups, and Oniguruma named conditional groups are silently invalid in ECMAScript and will throw SyntaxError.
  • It will not test performance. Browser RegExp does not expose step counts; for serious profiling use regex101 in PCRE mode or a real benchmark harness.

Your patterns and test strings are evaluated entirely in this browser tab. Nothing is sent to any server — paste production data without worrying about leaking it.

Frequently asked questions

Why does my pattern match "abc" but not match the same "abc" inside a longer string?

You probably have ^...$ anchors. ^ matches the start of the entire input (or the start of a line with the m flag), and $ matches the end. Remove them, or add the m flag if you want per-line anchoring.

How do I match a literal dot?

Escape it: \. — outside a character class, an unescaped . matches any character except newline (or any character at all with the s flag).

Why does (foo|bar)+ behave strangely on long inputs?

Capturing groups inside a + only retain the last iteration's capture, not all of them. If you want all matches, use the g flag with .matchAll() in JavaScript and iterate. For non-capturing alternation use (?:foo|bar) — it is slightly faster and signals intent.

Does this tester support PCRE features like (*ATOMIC) or possessive quantifiers?

No. JavaScript regex has neither. If your pattern uses them, you are reading PCRE documentation by mistake. The closest you get in V8 is the y flag for sticky matching, which solves a different problem (resumable scanning).

How do I do a lookbehind?

Use (?<=foo)bar to match "bar" preceded by "foo", and (?<!foo)bar for "not preceded by". Both are supported in all current evergreen browsers and Node 10+. Unlike PCRE, JavaScript lookbehinds support variable-length patterns.

Why does \d sometimes match Arabic-Indic or Devanagari digits?

Only with the u flag combined with v-mode in newer engines. By default \d in ECMAScript is the ASCII subset [0-9]. If you actually want Unicode digits, use [\p{Nd}] with the u flag.

Related tools

Last updated · E-Utils editorial team