\p{…} — a character by what it is, not what it looks like¶
One line: \p{L} is any letter, \p{Greek} any character of the Greek script, \p{Nd} any decimal digit — in Perl, PCRE2, Ruby, Java, Go, Rust and JavaScript-with-u; Python's re has none of it, JavaScript without u reads \p{L} as the text p{L}, and the spellings for a script (Greek / Script=Greek / IsGreek) are accepted by different subsets of the rest.
Level: reference · one construct, eight engines — the lesson has the depth
What it means¶
A property names a set defined by the Unicode Character Database rather than by listing characters. Three kinds matter in patterns:
| Kind | Examples | Asks |
|---|---|---|
| General category | \p{L}, \p{Lu}, \p{Nd}, \p{P} |
is it a letter / an uppercase letter / a decimal digit / punctuation |
| Script | \p{Greek}, \p{Cyrillic}, \p{Han} |
which writing system |
| Binary property | \p{Alphabetic}, \p{White_Space}, \p{Emoji} |
does it have this Boolean property |
\P{…} is the complement; \pL (no braces) is allowed for one-letter names in some engines; inside a class, [\p{L}\p{Nd}_] composes.
Measured¶
Verified output of kw_unicode_property_sh.sh — regenerated by tools/run_examples.py, never hand-typed.
construct python perl node ruby java go rust fancy
\p{L} letter - \u{3B1}b no \u{3B1}b \u{3B1}b \u{3B1}b \u{3B1}b \u{3B1}b
\p{L} node u flag - \u{3B1}b \u{3B1}b \u{3B1}b \u{3B1}b \u{3B1}b \u{3B1}b \u{3B1}b
\pL no braces - \u{3B1}b no no \u{3B1}b \u{3B1}b \u{3B1}b \u{3B1}b
\p{Lu} uppercase - \u{394} no \u{394} \u{394} \u{394} \u{394} \u{394}
\p{Greek} - \u{3B1}\u{3B2} no \u{3B1}\u{3B2} - \u{3B1}\u{3B2} \u{3B1}\u{3B2} \u{3B1}\u{3B2}
\p{Script=Greek} - \u{3B1} no - \u{3B1} - \u{3B1} \u{3B1}
\p{IsGreek} - \u{3B1} no - \u{3B1} - \u{3B1} \u{3B1}
\P{L} not a letter - 1 no 1 1 1 1 1
\p{Nd} decimal digit - \u{660} no \u{660} \u{660} \u{660} \u{660} \u{660}
Reading the table¶
- Python's column is
-all the way down.rehas no\p, and refuses it at compile time — the loud failure. (The third-partyregexmodule has the full set.) - Rows 1–2,
\p{L}in JavaScript. Withoutu:no, because the pattern is the five literal charactersp{L}+. Withu: the letters. The flag does not "enable Unicode"; it changes which grammar the pattern is parsed with. - Row 3,
\pL. Perl, Java, Go and Rust accept the brace-less form. JavaScript withoutureads it as the textpL… and Ruby compiles it and matches nothing — Onigmo reads\pLas the literalpL, warning on stderr. Two engines with a silent trap, from two different causes. - Rows 5–7, three spellings of one script.
\p{Greek}: everyone but Java.\p{Script=Greek}: everyone but Ruby and Go.\p{IsGreek}: Perl, Java and Rust only — and that is the spelling most likely to arrive by being copied out of Perl code, and it is a runtime error in PCRE2, so in ABAP. There is no spelling all six accept. - Rows 8–9.
\P{L}and\p{Nd}are the portable core: same answer in every engine that has properties at all.\p{Nd}matching U+0660 is why it is the right way to say "digit" when\dis ASCII in your engine.
The trap¶
Java's \p{Alpha}. It looks like a property and it is a POSIX ASCII class; \p{IsAlphabetic} or \p{L} is the Unicode one. The POSIX classes page has the row.
Where it is measured in depth¶
- Naming a Unicode property:
\p{...}— fifteen spellings across six engines, set operations in Rust,\X, and the pcre2grep real run for ABAP.
See also¶
- Shorthand classes —
\dand\w, which these replace when they are ASCII. - Grapheme cluster
\X· Case-insensitive matching. - Unicode text.