Regular Expressions Cheatsheet
Unicode
Use this Regular Expressions reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
Property escapes
\p{...} matches one code point with that Unicode property, \P{...} negates it.
| Escape | Matches |
|---|---|
\p{L} | any letter, any script |
\p{Lu} \p{Ll} | uppercase, lowercase letter |
\p{N} / \p{Nd} | any number / decimal digit |
\p{P} | punctuation |
\p{Zs} | space separator |
\p{M} | combining mark |
\p{C} | control and other |
\p{Alpha} \p{White_Space} | binary properties |
\p{Script=Greek} | code points whose script is Greek |
\p{Script_Extensions=Greek} | Greek plus code points shared with it |
\p{Emoji_Presentation} | default-emoji-rendering code points |
/^\p{L}+$/u.test("café"); // true
/\p{Script=Greek}+/u.exec("aαβ")[0]; // "αβ"
/\p{Lu}/u.test("A"); // true
/^\p{Nd}+$/u.test("٣٤"); // true, Arabic-Indic digitsJavaScript requires the u or v flag. Without it, /\p{L}/ does not throw, it matches the literal text p{L}. That silent failure is the single most common Unicode regex bug in JS.
Support by flavor
| Flavor | \p{...} |
|---|---|
| JavaScript | yes, with u or v |
| PCRE2 / PHP | yes, needs /u in PHP for UTF-8 |
| Java | yes, \p{IsGreek}, \p{IsAlphabetic}, \p{L} |
| .NET | yes |
| Go RE2 | yes, \p{Greek}, \p{L}, no Script= prefix |
| Ruby | yes |
Python re | no, \p is a bad-escape error |
Python regex package | yes |
grep -P | yes, PCRE |
grep -E / POSIX | no, use [[:alpha:]] |
# Python re has no \p, install the regex package for it import regex regex.findall(r'\p{Greek}+', 'aαβ') # ['αβ'] # or fall back to what re does give you import re re.findall(r'\w+', 'café') # ['café'], \w is Unicode-aware in re
What the shorthand classes mean per flavor
| Flavor | \d | \w | \b |
|---|---|---|---|
Python re (default) | any Unicode digit | Unicode letters, digits, _ | Unicode-aware |
Python re with re.A | [0-9] | [A-Za-z0-9_] | ASCII |
JavaScript, with or without u | [0-9] always | [A-Za-z0-9_] always | ASCII |
| Java | [0-9] unless UNICODE_CHARACTER_CLASS | same | same |
| PCRE | [0-9] unless /u and PCRE2_UCP | same | same |
| Go RE2 | [0-9] | [0-9A-Za-z_] | ASCII |
re.fullmatch(r'\w+', 'café') # matches re.fullmatch(r'\w+', 'café', re.A) # None re.match(r'\d', '٣') # matches, Arabic-Indic three
In JavaScript, use \p{Nd} for "any digit" and [\p{L}\p{N}_] for a Unicode \w. In Go, spell it [\p{L}\p{Nd}_].
Code units, code points, and graphemes
Three different lengths for the same visible text.
| Text | Graphemes | Code points | UTF-16 units |
|---|---|---|---|
é (precomposed U+00E9) | 1 | 1 | 1 |
é (e + U+0301) | 1 | 2 | 2 |
👨 | 1 | 1 | 2 |
👨👩👧 (family, ZWJ) | 1 | 5 | 8 |
"👨".match(/./g).length; // 2, surrogate halves, no u flag "👨".match(/./gu).length; // 1, u makes . one code point [..."👨👩👧"].length; // 5, still not 1
. and {n} count code points at best, never graphemes. ^.{1,10}$ on user input rejects a ten-emoji string and accepts a one-character string with fifty combining marks. Count with the host language instead, Intl.Segmenter in JavaScript or the regex module's \X in Python.
const g = [...new Intl.Segmenter().segment("👨👩👧a")]; g.length; // 2
Normalize before you match
The same word can be two different strings. NFC composes, NFD decomposes.
const a = "café"; // U+00E9 const b = "café"; // e + combining acute a === b; // false /^café$/u.test(b); // false a.normalize("NFC") === b.normalize("NFC"); // true
import unicodedata as ud ud.normalize('NFC', 'café') == 'café' # True
Normalize to NFC on the way in, then match. For search, normalize and strip marks: NFD, drop \p{M}, and you have a fold-insensitive key.
// "Crème Brûlée" -> "creme brulee" s.normalize("NFD").replace(/\p{M}+/gu, "").toLowerCase();
The v flag, set operations
JavaScript's v flag (ES2024) is u plus real set algebra inside a class. u and v are mutually exclusive.
| Syntax | Meaning |
|---|---|
[\p{L}--\p{Lu}] | letters except uppercase, difference |
[\p{L}&&\p{ASCII}] | letters that are ASCII, intersection |
[\p{L}\p{N}] | union, as always |
[\q{abc|xyz}] | match a multi-code-point string |
\p{RGI_Emoji} | one whole recommended emoji, ZWJ sequences included |
/^[\p{L}--\p{Lu}]$/v.test("a"); // true
/^[\p{L}--\p{Lu}]$/v.test("A"); // false
/^[\p{L}&&\p{ASCII}]$/v.test("é"); // false
/^\p{RGI_Emoji}$/v.test("👨👩👧"); // trueUnder v, [, (, {, /, -, | and the double punctuators must be escaped inside a class. Existing u patterns are not always v-clean, so change the flag deliberately rather than as a blanket upgrade.