Skip to content
Reference Template5 columns · 6 sample rows· Updated

Regular Expression (RegEx) Syntax Reference Markdown Table Template

A regex reference table earns its place in a README or wiki when it documents the patterns a team actually relies on: what each token means, which input it accepts, and which near-miss it rejects. Developers consult it while writing validation code, reviewers use it to check that a pattern in a pull request does what its comment claims, and support or QA staff read it to understand why an input was refused.

Edit This Template

Edit cells, add rows, or sort — the Markdown updates live
Row
1
^ and $
Beginning (^) and end ($) of entire string or line
^hello$ matches "hello"
"hello world" (fails $)
2
\d and \D
Digit (\d: [0-9] in JS; any Unicode digit in Python 3) or non-digit (\D)
\d+ matches "2025"
"abc" (fails \d)
3
\w and \W
Word character (\w: [A-Za-z0-9_] in JS; Unicode letters, digits and _ in Python 3) or non-word (\W)
\w+ matches "user_id"
"hello@world" (@ fails \w)
4
+ vs * vs ?
One or more (+), zero or more (*), zero or one (?)
a+ matches "aaa"
"" (empty string fails +)
5
{n,m}
\d{4} matches "2025"
"123" (requires 4 digits)
6
(?=...)
\w+(?=@) matches "user" in "user@site"
"user" without @
Output
| RegEx Token       | Pattern Category | Matching Behavior                                                                                           | Example Match                                | Non-Matching Example             |
| :---------------- | :--------------: | :---------------------------------------------------------------------------------------------------------- | :------------------------------------------- | :------------------------------- |
| `^` and `$`       |      Anchor      | Beginning (`^`) and end (`$`) of entire string or line                                                      | `^hello$` matches `"hello"`                  | `"hello world"` (fails `$`)      |
| `\d` and `\D`     | Character class  | Digit (`\d`: `[0-9]` in JS; any Unicode digit in Python 3) or non-digit (`\D`)                              | `\d+` matches `"2025"`                       | `"abc"` (fails `\d`)             |
| `\w` and `\W`     | Character class  | Word character (`\w`: `[A-Za-z0-9_]` in JS; Unicode letters, digits and `_` in Python 3) or non-word (`\W`) | `\w+` matches `"user_id"`                    | `"hello@world"` (`@` fails `\w`) |
| `+` vs `*` vs `?` |    Quantifier    | One or more (`+`), zero or more (`*`), zero or one (`?`)                                                    | `a+` matches `"aaa"`                         | `""` (empty string fails `+`)    |
| `{n,m}`           |    Quantifier    | Matches between n and m repetitions of preceding token                                                      | `\d{4}` matches `"2025"`                     | `"123"` (requires 4 digits)      |
| `(?=...)`         |    Lookaround    | Positive lookahead asserting condition follows without consuming                                            | `\w+(?=@)` matches `"user"` in `"user@site"` | `"user"` without `@`             |
6 rows × 5 columns
Rendered Preview
RegEx TokenPattern CategoryMatching BehaviorExample MatchNon-Matching Example
^ and $AnchorBeginning (^) and end ($) of entire string or line^hello$ matches "hello""hello world" (fails $)
\d and \DCharacter classDigit (\d: [0-9] in JS; any Unicode digit in Python 3) or non-digit (\D)\d+ matches "2025""abc" (fails \d)
\w and \WCharacter classWord character (\w: [A-Za-z0-9_] in JS; Unicode letters, digits and _ in Python 3) or non-word (\W)\w+ matches "user_id""hello@world" (@ fails \w)
+ vs * vs ?QuantifierOne or more (+), zero or more (*), zero or one (?)a+ matches "aaa""" (empty string fails +)
{n,m}QuantifierMatches between n and m repetitions of preceding token\d{4} matches "2025""123" (requires 4 digits)
(?=...)LookaroundPositive lookahead asserting condition follows without consuming\w+(?=@) matches "user" in "user@site""user" without @

When to Use This Table

The trap is that “regex” is not one language. JavaScript, Python’s re, PCRE2 (PHP, and grep -P in GNU grep), Java, .NET, and Go’s RE2-based regexp agree on the basics and diverge on details that matter: whether \d matches Arabic-Indic digits, whether lookbehind exists, whether $ matches before a trailing newline. A cheat table that does not name its flavor is quietly wrong for some of its readers, so state the engine and flags at the top.

A good table pairs every token with a tested example that shows the exact substring matched and a counter-example chosen to fail for the reason the token exists. A poor one shows \d+ matching 2025 and calls it done, never mentions anchors or flags, and breaks in the renderer because an alternation pipe split the row in two.

Formatting This Table in Markdown

A regular expression (regex) syntax reference table puts a few things in cells that Markdown treats as syntax. These are the ones to watch so it renders correctly on GitHub, GitLab, Obsidian and docs sites.

  • Put every token in a code span, even simple ones

    Outside backticks, Markdown consumes regex characters: a bare a\.b loses its backslash, a bare x*y*z italicizes the y, a bare [a-z](foo) becomes a link, and a bare <div> is read as an HTML tag and can disappear. Inside a code span all of these stay literal.

  • Escape alternation pipes, or move the pattern out

    Cells are split before code spans are parsed, so alternation is written (jpg\|png) in the source; see escaping pipes. A regex that matches a literal pipe is \|, and on cmark-gfm (the parser behind GitHub’s renderer) its table source is \\|; other renderers may differ, so show patterns with several pipes in a fenced block under the table.

  • Sample inputs turn into links outside code spans

    A table about matching emails and URLs often lists user@example.com or www.example.com as input; left bare, GFM autolinks both, so the cell shows a link instead of the string. Wrap each input in a code span and quote it so spaces and empty strings stay visible; on GitHub, two bare $ anchors in one cell may also pair up as math delimiters.

What Goes in Each Column

ColumnAlignmentWhat to put here
RegEx Tokenleft :---The token as typed inside a pattern, in backticks, without /…/ delimiters or string-literal doubling: \d, not "\\d". Group complementary tokens in one row (\d and \D). Any alternation bar must be written as \|, even inside the code span, or the row splits.
Pattern Categorycenter :---:One label from a short, fixed list (Anchor, Character class, Quantifier, Group, Lookaround, Flag), centered and always singular. Consistent labels let readers sort the table and stop it collecting near-duplicates such as “Anchors” and “Anchor”.
Matching Behaviorleft :---What the token matches and what changes that behaviour: the m flag for ^ and $, the s flag for ., Unicode mode for \w and \d. When flavors differ, say which one the sentence describes rather than giving the ASCII definition as universal.
Example Matchleft :---Pattern, input, and the exact substring matched: \d+ on "Order 2025" matches 2025. Showing the substring reveals whether the token matched the whole input or only part of it, which is the distinction most validation bugs come from.
Non-Matching Exampleleft :---A near miss that fails for the reason this token exists, with that reason in parentheses: "12a4" against ^\d{4}$ fails at a. Unrelated strings such as "abc" against a digit pattern teach nothing that the behaviour column does not already say.

How to Fill It In

  1. 1Write the target flavor and default flags above the table, for example “JavaScript (ECMAScript 2018+), no flags unless shown”. If the team uses two engines, such as a JavaScript front end and a Python back end, add a flavor-difference table rather than averaging them.
  2. 2Collect the tokens from patterns in use: search the codebase for new RegExp(, regex literals, re.compile(, and validation schemas. Document those first; a token nobody uses can wait.
  3. 3Test every example in the real engine. Use regex101 with the matching flavor selected, or one-liners such as node -e and python3 -c, and confirm both the match and the non-match. Copy the matched substring from the tool output.
  4. 4Escape for Markdown last: replace every | in a cell with \| (see escaping pipes), keep single backslashes, and preview the rendered table on the platform where it will live.
  5. 5Move the examples into unit tests next to the code that uses the patterns, so a change in a validator fails CI instead of silently contradicting the documentation.

Ready-to-Paste Variations

Flavor differences that bite

For teams running the same pattern in more than one engine. Check your exact runtime version before relying on a newer feature.

| Feature | JavaScript | Python `re` | PCRE2 | Go `regexp` |
| :--- | :---: | :---: | :---: | :---: |
| Lookahead `(?=…)` `(?!…)` | Yes | Yes | Yes | No |
| Lookbehind `(?<=…)` `(?<!…)` | Yes (ES2018) | Fixed width only | Yes, bounded length | No |
| `\d` matches non-ASCII digits | No | Yes, for `str` patterns | Only with UCP | No |
| POSIX class `[[:alpha:]]` | No | No | Yes | Yes |
| Named group | `(?<name>…)` | `(?P<name>…)` | Both forms | `(?P<name>…)` |
| Backreference `\1` | Yes | Yes | Yes | No |
| Atomic group `(?>…)` | No | Yes (3.11+) | Yes | No |

Lookaround assertions

All four zero-width assertions, each with an input and the exact text matched. The assertion checks its context without including it in the match.

| Assertion | Syntax | Pattern | Input | Matched text |
| :--- | :---: | :--- | :--- | :--- |
| Positive lookahead | `(?=…)` | `\w+(?=@)` | `user@site` | `user` |
| Negative lookahead | `(?!…)` | `q(?!u)` | `Iraq` | `q` (no match in `queen`) |
| Positive lookbehind | `(?<=…)` | `(?<=#)\d+` | `issue #42` | `42` |
| Negative lookbehind | `(?<!…)` | `(?<!-)\b\d+` | `-5 and 7` | `7` |

Alternation with escaped pipes

Every | in these cells is written as \| in the source and renders as a plain bar. Note the anchor row: alternation has the lowest precedence of any operator.

| Pattern | Meaning | Matches | Does not match |
| :--- | :--- | :--- | :--- |
| `cat\|dog` | Either word, anywhere | `hotdog` (finds `dog`) | `cow` |
| `^(cat\|dog)$` | Exactly one of the words | `cat` | `cats` |
| `^cat\|dog$` | Starts with `cat`, or ends with `dog` | `catalog` | `hotdogs` |
| `\.(?:jpe?g\|png)$` | Extension, without capturing | `photo.jpeg` | `photo.gif` |
| `\x7C` | A literal pipe, no bar in the pattern | `a\|b` | `a/b` |

Common Mistakes

  • Leaving | unescaped in an alternation such as (jpg|png).

    GFM splits cells on every unescaped pipe, including inside backticks, so the row gains a column and the pattern is cut in half. Write (jpg\|png); GitHub removes the backslash when rendering the code span.

  • Documenting \d as [0-9] and \w as [A-Za-z0-9_] for every language.

    That holds in JavaScript and Go, but Python 3 str patterns match any Unicode digit and word character unless you pass re.ASCII. If only ASCII digits are valid, write [0-9] explicitly and say why.

  • Validating whole inputs with ^…$ in Python.

    Python’s $ also matches just before a trailing newline, so re.match(r"^\d+$", "123\n") succeeds. Use re.fullmatch() or end the pattern with \Z.

  • Assuming . matches everything.

    By default . does not match line terminators. Enable the s flag (dotAll in JavaScript since ES2018, re.DOTALL in Python) or use [\s\S] when a pattern must cross lines, and note the flag in the behaviour column.

  • Greedy quantifiers in examples that only work on tidy input.

    <.+> on <b>bold</b> matches the whole string, not the first tag. Show the lazy form <.+?> or a negated class <[^>]+>, and pick example inputs that contain more than one candidate match.

Browse all 50 templates
FAQ

Regular Expression (RegEx) Syntax Reference: Frequently Asked Questions

Does JavaScript support lookbehind?

Yes, since ES2018, with no fixed-width restriction, and all current major browsers support it (Safari since 16.4). In an engine without support, a regex literal using it is a syntax error that stops the whole script from parsing, so check your oldest supported browser.

Why does \w not match accented letters in JavaScript?

In JavaScript, \w is ASCII-only even with the u flag. To match letters in any script, use a Unicode property escape with the u flag, such as /[\p{L}\p{N}_]+/u, which matches é, ß, and letters from non-Latin alphabets.

What is the difference between * and *?

Both repeat zero or more times. * is greedy: it takes as much as possible and then backtracks. *? is lazy: it takes as little as possible and extends only when the rest of the pattern fails. The same applies to +?, ??, and {n,m}?.

Which flavor does grep use?

Plain grep uses POSIX basic syntax, grep -E uses extended syntax, and GNU grep -P uses PCRE. POSIX syntax has no \d, so write [0-9] or [[:digit:]] in shell scripts that must run with any grep.