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…)。