\p{…} 属性类:用码点的 Unicode 档案来匹配
字符的编码 那页讲了字符的编号(code point)与存储(UTF-16 / UTF-8)。这页讲第三样:每个编号在 Unicode Character Database(UCD) 里都有一份档案——名字、General_Category(它是字母 / 数字 /
标点……)、Script(它属于哪套文字),外加几十个二元属性(White_Space?Math?…… 的勾选框)。\p{…} 就是「按档案匹配」:不必手写 [一-鿿] 这种码位区间,直接说「我要 \p{Script=Han}」。\P{…} 是取反;两者都必须开 u 或
v 标志——没有标志时 \p 只是字面量 p。
1 · \p{…} 的三种合法写法
| 写法 | 查档案的哪一栏 | 例子 |
|---|---|---|
\p{L} / \p{Lu} |
General_Category(可省 gc=) |
\p{L} ≡ \p{gc=L} ≡ \p{General_Category=L} |
\p{Script=Han} |
Script / Script_Extensions | \p{sc=Han}、\p{scx=Han} |
\p{White_Space} |
二元属性(名字单独写) | \p{Math}、\p{Alphabetic}、\p{Emoji} |
注 · 单独写一个名字时(\p{X}),引擎按「二元属性名,或 General_Category 的值」解析——所以 \p{L} 是 gc 缩写、\p{Math} 是二元属性,写法看着一样,查的栏不同。拼写是严格的:大小写、下划线都不能错,\p{whitespace} 直接
SyntaxError。没有第四种——档案里还有一栏 Block(住址),JS 的 \p{} 不支持,见本页第 6 节。
2 · 码点探针
用原生 /\p{…}/u 把一个字符的档案逐栏测出来。几个反直觉的例子:𝑥(数学斜体)是字母、Script 却是 Common;、(顿号)不是 sc=Han;½ 是数字(N)却不是十进制数字(Nd)。
3 · 第一栏 General_Category
每个码点恰好属于一个 gc 小类;小类首字母就是大类。
| 大类 | 含义 | 码点数 | 小类 | 例子 |
|---|---|---|---|---|
\p{L} |
Letter 字母 | 145 672 | Lu Ll Lt Lm Lo |
A é 中 ٱ 𝑥 |
\p{M} |
Mark 标记(组合用) | 2 543 | Mn Mc Me |
é 拆开后的 ◌́ |
\p{N} |
Number 数字 | 1 924 | Nd Nl No |
7 ٧ Ⅻ ① ½ |
\p{P} |
Punctuation 标点 | 856 | Pc Pd Ps Pe Pi Pf Po |
, 、 « » _ |
\p{S} |
Symbol 符号 | 8 617 | Sm Sc Sk So |
+ € ^ 😀 |
\p{Z} |
Separator 分隔 | 19 | Zs Zl Zp |
空格 NBSP 全角空格 |
\p{C} |
Other 其他 | 954 481 | Cc Cf Cs Co Cn |
控制符 ZWJ 未分配区 |
注 · \p{C} 是大头,因为 U+0000~U+10FFFF 共 1 114 112 个码位里大部分还没分配(Cn)。另外 emoji 😀 的 gc 是 So(其他符号)——「是不是 emoji」记在二元属性栏,不在 gc 栏。\p{P} 标点的七个子类、脚注符号为什么全是
Po,见 \p{P} 标点七子类。
把一段文本逐码点按大类着色,就能看清 gc 怎么切分真实文本。
4 · \w \d 的 ASCII 视野
\w \d 是钉死的 ASCII 集合:\w = [A-Za-z0-9_]、\d = [0-9],开了 u 也不变。要按「档案」理解的字母 / 数字,得用 \p{L} / \p{Nd}。
\\w \\d 与按档案匹配的 gc 属性类下的命中对照,每格实时测出。
警示 · 三个易错点。其一,国际化校验「是字母」要用 \p{L},\w 连 é 都不认。其二,\p{Nd}(十进制位)不等于 \p{N}(一切数字)——① ½ Ⅻ 是 N 却非 Nd,解析数值时别把
½ 当数位收进来。其三,_ 在 \w 里却既非字母也非数字,它的 gc 是 Pc 连接标点。
5 · 第二栏 Script 与 sc / scx 之辨
Script(sc) 给每个码点记一个主属文字;但很多字符是几套文字共用的——顿号 、 中日韩都用,长音符 ー 平假名片假名都用,它们的 sc 只能记 Common。Script_Extensions(scx) 记的才是「哪些文字在用它」这个集合。
建议 ·「提取一段汉字 / 假名 / 谚文」用 \p{scx=…} 通常更接近直觉——\p{sc=Han} 会把 、 。 这些 CJK 标点漏在外面,它们 sc=Common。顺带一提,𝕏 𝑥 这类数学字母的 Script 也是
Common——「长得像哪国字」不等于「属于哪套文字」。
6 · 第三栏二元属性
gc 和 Script 每栏只有一个值;二元属性则是一排独立的 Yes/No 勾选框,一个码点可以同时勾中好几个。JS 支持几十个,常用的如 \p{White_Space}、\p{Math}、\p{Alphabetic}、\p{Uppercase}、\p{ASCII},以及
emoji 六属性 整页在讲的 \p{Emoji} 一家。
\p{White_Space}(25 个)与 \s 两份名单高度重合但不相等:
\\s 与 White_Space 属性类下的命中对照。差异恰好落在 BOM 与 NEL 两处。
警示 · 差异恰好两处:BOM U+FEFF 算 \s 却不算 \p{White_Space}(ES 把 ZWNBSP 纳入 WhiteSpace,Unicode 档案里它是 Cf 格式字符);NEL U+0085 算 \p{White_Space} 却不算 \s。其余成员一致——空白与换行
的完整清单讲的就是 \s 这份名单。
\p{Math}(2322 个)与 \p{Sm}(960 个)则展示了二元属性可以跨着 gc 切:
注 · 𝑥(数学斜体)、ℵ(阿列夫)gc 都是字母,却勾了 Math;普通的 x 反而 Math=No。这正是二元属性的价值:「数学符号」这个概念横跨 Sm / L / P 好几个 gc 类,只有档案里单独一栏才装得下。同理 \p{Alphabetic}(147
421)也比 \p{L}(145 672)大——多出 Nl 与一批组合标记。2322 个 Math 字符的全名单见 \p{Math} 全量速查。
7 · Block 那一栏 JS 不支持
档案里还有一栏 Block:码点住在哪个连续码位区段,比如 ∑ 住在 Mathematical Operators(U+2200~22FF)、中 住在 CJK Unified Ideographs(U+4E00~9FFF)。但 JS 的 \p{} 只支持 gc / Script(_Extensions) / 二元属性三种,Block 写法直接
SyntaxError(Java 的 \p{InGreek}、.NET 的 \p{IsGreek}、Python regex 模块的 \p{Block=…} 才有)。想按 block 匹配,JS 只能手写码位区间。
警示 · 而且 block 是住址、不是身份,就算能用也常不是想要的。其一,同一个 block 里能住好几套文字——CJK Symbols and Punctuation 区里的 、 Script 是 Common。其二,同一类字符散落在多个 block——上图实测里 ± × ÷ 住 Latin-1、𝑥 住
Mathematical Alphanumeric Symbols,手写 U+2200~22FF 区间全漏掉,而 \p{Math} 一个不漏。按「身份」查档案,几乎总比按「住址」圈选区间更可靠。
建议 · 页首探针的「住址」栏之所以查得到,是因为本系列 regex.ts 内嵌了一份官方 Blocks.txt(Unicode 17.0.0)的区间表,blockOf(cp) 二分一查就知道任意码点的住址。
8 · 全量速查:346 个 block 的住址簿
Unicode 17.0.0 共 346 个具名 block,其余空隙是 No_Block。按码位平面分段,搜索支持三种查法:块名(忽略大小写 / 空格 / 连字符,如 superscript、latin1)、码点 hex(如 2070 或 U+2070),或直接粘一个字符。
建议 · 和别的页串起来看:空白与换行 的 \s 完整清单对应这页的 White_Space 勾选框;emoji 六属性 讲的 \p{Emoji} 一家就是六个二元属性;自研引擎
的 @vega/parsing/regex 同样支持 gc / sc / scx / 二元属性三种写法、同样不支持 Block——名字解析也按 JS 的严格拼写来。