All articles

Regular expressions: basic syntax and common patterns

A regular expression (regex) is a compact way to describe a text pattern: not a specific string, but a rule a string must match. Instead of looping character by character, you can check for or find a complex structure with a single expression.

Basic building blocks

  • Character classes\d (digit), \w (letter/digit/underscore), \s (whitespace), or a custom class like [a-zA-Z].
  • Quantifiers* (0 or more), + (1 or more), ? (0 or 1), {2,5} (2 to 5 times).
  • Capture groups — parentheses (...) mark a part of the match that can be used separately later, for instance in a replacement.
  • Anchors^ and $ tie a pattern to the start or end of a line.

One name, several incompatible dialects

"Regex" isn't one language — it's a family. Python's re module, PCRE (used by PHP and, historically, by many other tools), POSIX basic/extended regex (used by grep and sed), and JavaScript's native RegExp all diverge on real syntax details: named groups are written (?P<name>...) in Python and older PCRE but (?<name>...) in JavaScript and modern PCRE; lookbehind ((?<=...)) only became fully supported in JavaScript with ES2018, years after Python and PCRE already had it. A pattern copied from a Python script into a JavaScript project can fail to compile for reasons that have nothing to do with the pattern's logic.

Greedy vs lazy matching

By default, quantifiers are "greedy" — they try to consume as many characters as possible, backing off only if that prevents a match. For example, <.+> on <a>text</a> would capture everything from the first < to the very last >. Adding ? after a quantifier (<.+?>) makes it "lazy" — it consumes as little as possible, stopping at the first valid match.

Why you need this

  • Validating the format of input data (email, phone number, postal code).
  • Finding and bulk-replacing text based on a pattern rather than an exact match.
  • Extracting structured data from logs or unstructured text.

Catastrophic backtracking

Nested quantifiers like (a+)+ can, on certain inputs, force a regex engine to try an exponential number of combinations before concluding there's no match — the page or server "freezes" on what looks like a simple expression. This is a real vulnerability class (ReDoS), so complex nested quantifiers should be stress-tested against long "near-match" strings, not just the expected examples.

Try the tool