Skip to content
Dev Tools2026-08-283 min read

Symptom: it should match but doesn't

You write what looks like a correct pattern in a regex tester, and either nothing highlights, or it grabs one weird chunk. The two most common cases:

  • You use .* to grab content, but it swallows everything from start to end;
  • The pattern "looks right" but matches nothing at all.

Here are the frequent traps, explained once.

Trap 1: greedy quantifiers swallow everything

The * in .* is greedy — it matches as much as possible before giving back. With multiple blocks in the text:

<div>A</div><div>B</div>

Using |<div>.*</div>| matches greedily all the way to the last </div>, folding both "A" and "B" into one match.

| Pattern | Meaning | Behavior | |---|---|---| | .* | greedy | matches as much as possible | | .*? | lazy (add ?) | matches as little as possible, stops at first close |

Change it to |<div>.*?</div>| and you get two separate matches for "A" and "B".

Trap 2: special characters not escaped

. + ? * ( ) [ ] { } ^ $ | \ all have special meaning in regex. To match them literally, escape with a backslash:

| You want | Write | |---|---| | a literal dot . | \. | | a literal plus + | \+ | | a literal paren ( | \( |

This is why "my email regex doesn't match the dot after @".

Trap 3: anchors and multiline mode

^ and $ match the start and end of the whole text by default. For line-by-line matching you must enable multiline mode (the m flag):

^error.*$    # without m: only the first line
^error.*$    # with m flag: every line starting with error

Trap 4: missing flags

| Flag | Effect | Symptom if missing | |---|---|---| | g (global) | match all, not just first | only one result returned | | i (ignore case) | case-insensitive | abc misses ABC | | m (multiline) | ^ $ per line | anchors fail on multiline text |

How to debug step by step

Open the Regex Tester on ToolVault:

  1. Paste your test text into the "test text" box;
  2. Type the pattern; matches highlight live on the right;
  3. Toggle g / i / m and watch the behavior change instantly;
  4. Use the "groups" view to confirm each capture group — avoid .* eating your target.

Everything runs locally; neither pattern nor text is uploaded.

FAQ

Is lazy .*? always better than greedy?

No. Lazy is better for "extract content between two delimiters"; greedy is better when you want "from here to end of line". Pick by need.

Why is a capture group undefined?

Often the parentheses became a character class [()] or were escaped \(, so no capture group formed; or your string has newlines but the s (dotAll) flag is off, so . can't match them.

Can Chinese be used directly outside meta chars?

Yes. Chinese are ordinary characters and match as-is; only the metacharacters listed above need escaping.


Provided by ToolVault. Related tools: JSON Formatter, API Tester, Mock Data Generator. Visit the home page for more developer tools.


Advertisement