\p{...}: Unicode property escapes, and the flag they need
\p{...} matches a character by its Unicode property, such as a letter, a decimal digit or a script. It requires the u flag, and without it the escape silently means a literal letter p.
At a glance
- Syntax
- \p{...} and its negation \P{...}
- Requires
- the u flag, with no exceptions
- Added in
- ES2018
- Common values
- L letter, Nd decimal digit, Lu uppercase letter, P punctuation
- Script form
- \p{Script=Greek} and \p{Script_Extensions=Greek}
- Without the u flag
- \p is read as a literal p, so /\p{L}/ matches the text p{L}
In detail
Property escapes are how you write a class that means something linguistic rather than numeric. \p{L} is any letter in any script, \p{Nd} is any decimal digit including Arabic-Indic and Devanagari, and \p{Lu} is any uppercase letter. None of that can be expressed as a code point range without listing dozens of them.
The flag requirement is absolute and the failure mode is silent. Without u, the backslash before the p falls through to the legacy compatibility rule, the escape becomes a plain letter p, and the braces are treated as literal text because they are not a valid quantifier. The result is a pattern that matches the four character string p{L}, compiles without complaint, and never matches anything you care about.
Scripts use a key and value form. \p{Script=Greek} matches characters whose script is Greek, and \p{Script_Extensions=Greek} is the more forgiving variant that also matches characters shared with Greek. For anything involving mixed script text the extensions form is usually the one you want.
The negated form \P{...} is the complement, and both work inside a character class, so [\p{L}\p{N}_] is a Unicode aware version of \w. That combination is the standard replacement for \w and \d in any pattern that has to accept real names or real numerals.
Examples
"café naïve".match(/\p{L}+/gu); // ["café", "naïve"]
/^\p{Script=Greek}+$/u.test("αβγ"); // true
/^[\p{L}\p{N}_]+$/u.test("naïve_2"); // true/\p{L}/.test("a"); // false
/\p{L}/.test("p{L}"); // true, that is what the pattern really means
/\p{L}/u.test("a"); // trueThings that catch people out
- Forgetting the u flag does not produce an error. The pattern compiles into a literal p followed by literal braces and matches almost nothing, which reads as a data problem rather than a pattern problem.
- \p{Alpha} and other POSIX style names are not supported. The value has to be a Unicode general category, script, or binary property name.
- Property escapes are ES2018, so a pattern using them will not compile in an older environment or in an engine that never adopted them.
Try it: Regex Tester
Type a pattern and a test string, watch every match highlight as you go, read a plain English breakdown of each token, and check the numbered and named groups it captured.
Regex Tester
LOCAL · Browser-OnlyTest and debug regular expressions with live matching and highlights
Related Regex syntax
All regex syntax →The u flag: Unicode mode
What the u flag changes about how a pattern is parsed, the escape forms it unlocks, and the previously tolerated syntax it turns into a hard error.
\d: the digit class, and the digits it refuses
In JavaScript \d is exactly [0-9], even with the u flag. Here is why other engines disagree and what to use when you need Unicode digits.
\w: the word character class, underscore included
\w is exactly [A-Za-z0-9_] in JavaScript. That includes the underscore and excludes every accented letter, which is where most \w bugs come from.
\b: word boundaries, underscores and accented letters
\b is a zero width assertion defined entirely in terms of \w, which is why user_name has no internal boundary and café has none at its end.
\B: the non word boundary and what it is good for
\B asserts that a position is not a word boundary, which turns it into an inside a word search. It also never matches at the edges of a word.
The * quantifier: zero or more, including nothing at all
The star quantifier succeeds even when it matches nothing, which is why a global match against it returns an empty string at almost every position.
Tools for this
- Regex Tester Free online regex tester - test and debug regular expressions with live matching and highlights
- Regex Playground Regex playground with live match highlighting, named groups, find and replace, and shareable links