March 8, 2026·8 min read·RegexBest Practices

Top 10 Regex Mistakes Developers Make (And How to Fix Them)

Regex is powerful — and easy to get subtly wrong. These mistakes range from patterns that silently match too much, to ones that can crash your server under load. Here are the 10 most common regex errors developers make, each with a broken example and the correct fix.

1. Using .* When You Mean [^x]*

.* matches everything, including the delimiter you're trying to stop at. This causes greedy over-matching that swallows more than intended.

❌ Wrong

/".*"/g
// Input: "hello" and "world"
// Matches: "hello" and "world"  ← entire span, not two separate strings

✅ Correct

/"[^"]*"/g
// Matches: "hello"  and  "world"  ← two separate matches

Use a negated character class [^delimiter]* to stop at the first occurrence of the delimiter. Reserve .* for cases where you genuinely want to match across any character.

2. Forgetting to Escape Special Characters

Characters like . * + ? ( ) [ { \ ^ $ | have special meaning in regex. Using them unescaped when you mean the literal character is a silent bug.

❌ Wrong

// Trying to match "3.14"
/3.14/
// Also matches: "3x14", "3 14", "3!14"  ← dot matches any char

✅ Correct

/3\.14/
// Only matches the literal string "3.14"

3. Missing Start/End Anchors on Validation Patterns

Without ^ and $ anchors, a validation pattern can match a substring of invalid input — making your validator silently pass bad data.

❌ Wrong

/\d{5}/
// Intended: validate a 5-digit ZIP code
// Also matches: "abc12345xyz"  ← finds 5 digits anywhere in string

✅ Correct

/^\d{5}$/
// Only matches a string that is exactly 5 digits, nothing else

Always anchor validation patterns. Use ^...$ when the entire string must match, or \b...\b for word-boundary matching within larger text.

4. Catastrophic Backtracking

Nested quantifiers like (a+)+ or (.*)* can cause exponential backtracking — the regex engine tries an astronomical number of combinations on certain inputs, hanging or crashing your application. This is a real security vulnerability (ReDoS).

❌ Wrong (ReDoS risk)

/(a+)+b/
// Input: "aaaaaaaaaaaaaaac"  ← no "b" at end
// Engine backtracks exponentially — hangs on long inputs

✅ Correct

/a+b/
// Flatten nested quantifiers; use possessive quantifiers
// or atomic groups where your engine supports them

Avoid nested quantifiers on overlapping patterns. If you must handle complex patterns on untrusted input, use a RE2-based engine (Go, or the re2 Python package) which guarantees linear time matching.

5. Using Greedy When You Need Lazy

By default, quantifiers are greedy — they match as much as possible. When extracting content between delimiters, greedy matching often grabs too much.

❌ Wrong (greedy)

/<.+>/g
// Input: "<b>bold</b> and <i>italic</i>"
// Matches: "<b>bold</b> and <i>italic</i>"  ← entire span

✅ Correct (lazy)

/<.+?>/g
// Matches: "<b>"  "</b>"  "<i>"  "</i>"  ← each tag separately

Add ? after a quantifier to make it lazy: *? +? ??. Lazy quantifiers match as little as possible. That said, a negated character class is often cleaner and faster than a lazy quantifier.

6. Forgetting the Global Flag for Multiple Matches

Without the g flag in JavaScript (or using search instead of findall in Python), your pattern only returns the first match.

❌ Wrong

"cat bat sat".match(/[a-z]at/)
// Returns: ["cat"]  ← only first match

✅ Correct

"cat bat sat".match(/[a-z]at/g)
// Returns: ["cat", "bat", "sat"]  ← all matches

7. Case Sensitivity Surprises

Regex is case-sensitive by default. Forgetting the case-insensitive flag leads to missed matches that are hard to debug.

❌ Wrong

/error/
// Misses: "Error", "ERROR", "eRrOr"

✅ Correct

/error/i          // JavaScript: i flag
re.compile(r'error', re.IGNORECASE)  // Python

8. Treating \d as Equivalent to [0-9]

In most engines, \d matches Unicode digit characters — not just ASCII 0–9. This includes Arabic-Indic digits (٠١٢٣...), Devanagari digits, and others. For strict ASCII digit matching, use [0-9].

❌ Potentially wrong

/^\d+$/
// In Python with re: matches "١٢٣" (Arabic-Indic digits)
// May pass validation when you expected only 0-9

✅ Correct (ASCII only)

/^[0-9]+$/
// Strictly matches ASCII digits only

9. Multiline Mode Confusion with ^ and $

By default, ^ and $ match the start and end of the entire string. In multiline mode (m flag), they match the start and end of each line. Mixing these up causes patterns to match (or not match) in unexpected places.

❌ Wrong (missing m flag)

const text = "line1\nERROR: something\nline3";
text.match(/^ERROR:.+/g)
// Returns: null  ← ^ only matches start of entire string

✅ Correct (with m flag)

text.match(/^ERROR:.+/gm)
// Returns: ["ERROR: something"]  ← ^ matches start of each line

10. Using Regex to Parse HTML or JSON

This is the classic mistake. HTML and JSON are not regular languages — they have nesting, escaping, and context that regex cannot reliably handle. Regex-based HTML parsing breaks on edge cases and is a maintenance nightmare.

❌ Wrong

// Extracting href from HTML with regex
/<a\s+href="([^"]+)"/g
// Breaks on: single quotes, extra attributes before href,
// multiline tags, encoded characters, self-closing tags...

✅ Correct

// Use a proper parser
// JavaScript: DOMParser or cheerio
const doc = new DOMParser().parseFromString(html, 'text/html');
const hrefs = [...doc.querySelectorAll('a')].map(a => a.href);

// Python: BeautifulSoup
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
hrefs = [a['href'] for a in soup.find_all('a', href=True)]

Use regex for extracting patterns from plain text. Use a dedicated parser for structured formats like HTML, XML, JSON, or CSV.

Quick Reference

#MistakeFix
1.* over-matchesUse [^x]* negated class
2Unescaped special charsEscape with \
3Missing anchors on validationAdd ^ and $
4Catastrophic backtrackingFlatten nested quantifiers
5Greedy when lazy neededAdd ? for lazy: +?
6Missing global flagAdd g flag / use findall
7Case sensitivityAdd i flag
8\d matches Unicode digitsUse [0-9] for ASCII only
9Multiline ^$ confusionAdd m flag for per-line anchors
10Parsing HTML/JSON with regexUse a proper parser

Write regex without the mistakes

Describe your pattern in plain English — RegSQL generates correct, explained regex with the right flags, anchors, and quantifiers already in place.

✨ Try RegSQL Regex Generator Free →