JavaScript 使用 Unicode 编码 来表示字符串。大多数字符使用 2 个字节进行编码,但这最多只能表示 65536 个字符。
这个范围不足以编码所有可能的字符,因此一些罕见的字符使用 4 个字节进行编码,例如 𝒳(数学 X)或 😄(微笑),一些象形文字等等。
以下是某些字符的 Unicode 值
| 字符 | Unicode | Unicode 中的字节计数 |
|---|---|---|
| a | 0x0061 |
2 |
| ≈ | 0x2248 |
2 |
| 𝒳 | 0x1d4b3 |
4 |
| 𝒴 | 0x1d4b4 |
4 |
| 😄 | 0x1f604 |
4 |
因此,像 a 和 ≈ 这样的字符占用 2 个字节,而 𝒳、𝒴 和 😄 的代码更长,它们有 4 个字节。
很久以前,当 JavaScript 语言被创建时,Unicode 编码更简单:没有 4 字节字符。因此,一些语言特性仍然无法正确处理它们。
例如,length 认为这里有两个字符
alert('😄'.length); // 2
alert('𝒳'.length); // 2
…但我们可以看到只有一个,对吧?关键是 length 将 4 个字节视为两个 2 字节字符。这是不正确的,因为它们必须被视为一个整体(所谓的“代理对”,您可以在文章 字符串 中阅读有关它们的更多信息)。
默认情况下,正则表达式也将 4 字节的“长字符”视为一对 2 字节字符。并且,正如字符串中发生的那样,这可能会导致奇怪的结果。我们将在稍后的文章 集合和范围 [...] 中看到这一点。
与字符串不同,正则表达式有标志 u 来解决这些问题。使用此标志,正则表达式可以正确处理 4 字节字符。并且 Unicode 属性搜索也变得可用,我们将在下一节中介绍它。
Unicode 属性 \p{…}
Unicode 中的每个字符都有许多属性。它们描述了字符属于哪个“类别”,包含有关它的各种信息。
例如,如果一个字符具有 Letter 属性,则表示该字符属于一个字母表(任何语言的字母表)。而 Number 属性表示它是一个数字:可能是阿拉伯数字或汉字,等等。
我们可以搜索具有特定属性的字符,写成 \p{…}。要使用 \p{…},正则表达式必须具有标志 u。
例如,\p{Letter} 表示任何语言中的字母。我们也可以使用 \p{L},因为 L 是 Letter 的别名。几乎每个属性都有更短的别名。
在下面的示例中,将找到三种类型的字母:英语、格鲁吉亚语和韩语。
let str = "A ბ ㄱ";
alert( str.match(/\p{L}/gu) ); // A,ბ,ㄱ
alert( str.match(/\p{L}/g) ); // null (no matches, \p doesn't work without the flag "u")
以下是主要字符类别及其子类别
- 字母
L- 小写字母
Ll - 修饰符
Lm, - 标题大小写
Lt, - 大写字母
Lu, - 其他
Lo.
- 小写字母
- 数字
N- 十进制数字
Nd, - 字母数字
Nl, - 其他
No.
- 十进制数字
- 标点符号
P- 连接符
Pc, - 连字符
Pd, - 起始引号
Pi, - 结束引号
Pf, - 左括号
Ps, - 右括号
Pe, - 其他
Po.
- 连接符
- 标记
M(重音等)- 间隔组合
Mc, - 封闭
Me, - 非间隔
Mn.
- 间隔组合
- 符号
S- 货币
Sc, - 修饰符
Sk, - 数学
Sm, - 其他
So.
- 货币
- 分隔符
Z- 行
Zl, - 段落
Zp, - 空格
Zs.
- 行
- 其他
C- 控制
Cc, - 格式
Cf, - 未分配
Cn, - 专用使用
Co, - 代理
Cs.
- 控制
因此,例如,如果我们需要小写字母,我们可以写 \p{Ll},标点符号:\p{P} 等等。
还有一些其他派生类别,例如
字母(Alpha),包括字母L,加上字母数字Nl(例如 Ⅻ - 罗马数字 12 的字符),加上一些其他符号Other_Alphabetic(OAlpha).Hex_Digit包括十六进制数字:0-9,a-f.- …等等。
Unicode 支持许多不同的属性,它们的完整列表需要很多空间,因此这里有一些参考资料
- 按字符列出所有属性:https://unicode.org/cldr/utility/character.jsp.
- 按属性列出所有字符:https://unicode.org/cldr/utility/list-unicodeset.jsp.
- 属性的简短别名:https://www.unicode.org/Public/UCD/latest/ucd/PropertyValueAliases.txt.
- 文本格式的完整 Unicode 字符集,包含所有属性,位于:https://www.unicode.org/Public/UCD/latest/ucd/.
示例:十六进制数字
例如,让我们查找十六进制数字,写成 xFF,其中 F 是十六进制数字 (0…9 或 A…F)。
十六进制数字可以用 \p{Hex_Digit} 表示
let regexp = /x\p{Hex_Digit}\p{Hex_Digit}/u;
alert("number: xAF".match(regexp)); // xAF
示例:汉字
让我们查找汉字。
Unicode 属性中有一个名为 Script(书写系统)的属性,它可以取值为:Cyrillic(西里尔字母)、Greek(希腊字母)、Arabic(阿拉伯字母)、Han(汉语)等等,这里有完整的列表。
要查找特定书写系统中的字符,可以使用 Script=<value>,例如,要查找西里尔字母,可以使用 \p{sc=Cyrillic},要查找汉字,可以使用 \p{sc=Han},等等。
let regexp = /\p{sc=Han}/gu; // returns Chinese hieroglyphs
let str = `Hello Привет 你好 123_456`;
alert( str.match(regexp) ); // 你,好
示例:货币
表示货币的字符,例如 $、€、¥,具有 Unicode 属性 \p{Currency_Symbol},简写别名为:\p{Sc}。
让我们用它来查找“货币符号后跟数字”格式的价格。
let regexp = /\p{Sc}\d/gu;
let str = `Prices: $2, €1, ¥9`;
alert( str.match(regexp) ); // $2,€1,¥9
稍后,在文章 量词 +、*、? 和 {n} 中,我们将学习如何查找包含多个数字的数字。
总结
标志 u 启用正则表达式中的 Unicode 支持。
这意味着两件事:
- 4 字节的字符被正确处理:作为一个单一字符,而不是两个 2 字节字符。
- Unicode 属性可以在搜索中使用:
\p{…}。
使用 Unicode 属性,我们可以查找特定语言的单词、特殊字符(引号、货币)等等。
评论
<code>标签,要插入多行代码,请将它们用<pre>标签包裹,要插入超过 10 行的代码,请使用沙箱(plnkr、jsbin、codepen…)。