Skip to content

\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. re has no \p, and refuses it at compile time — the loud failure. (The third-party regex module has the full set.)
  • Rows 1–2, \p{L} in JavaScript. Without u: no, because the pattern is the five literal characters p{L}+. With u: 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 without u reads it as the text pL… and Ruby compiles it and matches nothing — Onigmo reads \pL as the literal pL, 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 \d is 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

See also