原文链接:https://javascript.info/regexp-unicode,translate with ❤️ by zhangbao.
使用 Unicode 标记 /.../u
可以启用正则表达式对查找代理对的支持。
代理对在 字符串 一章里已经说过了。
在这里我们再简要的回忆下。简单说,正常一个字符使用 2 个字节编码,这样我们能获得最多 65535 个字符,但是后来有更多的字符出现了,用 2 个字节已经不够表示了。
所以,后来的字符使用了 4 个字节编码,像 𝒳
(数学里的 X)或者😄(微笑)。
下面我们来比较下不同字符的 Unicode 码:
字符 | Unicode | 字节 |
---|---|---|
a |
0x0061 | 2 |
≈ |
0x2248 | 2 |
𝒳 |
0x1d4d3 | 4 |
𝒴 |
0x1d4d4 | 4 |
😄 |
0x1f604 | 4 |
像 a
和 ≈
这样的字符占据 2 个字节,其他字符占据 4 个字节。
Unicode 是这样做的,4字节的字符表示一个整体的含义。
过去 JavaScript 并不知道这个,所以现在许多的字符串方法是有问题的。例如,length
属性会认为有两个字符:
alert( '😄'.length ); // 2
alert( '𝒳'.length );// 2
但是我们看到的只有一个啊,关键是 length
属性只认 2 个字节表示的字符,因为这些字符用 4 个字节表示,所以被 length
属性认为有 2 个字符。这是不对的,他们是一个整体(称为”代理对”)。
正常情况下,正则表达式也把”长字符”当成是 2 个用 2 个字节表示的字符。
这会导致奇怪的结果,例如我们从字符串”𝒳
“里查找 [𝒳𝒴]
:
alert( '𝒳'.match(/[𝒳𝒴]/) ); // 奇怪的结果
结果是错误的,因为默认正则引擎并不理解代理对。它认为 [𝒳𝒴] 并不是两个字符,而是四个字符:𝒳
的左半部分(1),𝒳
的右半部分(2),𝒴
字符的左半部分(3),𝒴
字符的右半部分(4)。
所以正则引擎在字符串 𝒳
中查找的是 𝒳
的左边一半,而不是整个符号。
换句话说,搜索类似 '12'.match(/[1234]/)
—— 返回了 1
(𝒳
的左边一半)。
/.../u
解决了这个问题,它启用了正则表达式查找代理对的能力,所以返回的结果是正确的:
alert( '𝒳'.match(/[𝒳𝒴]/u) ); // 𝒳
如果我们忘记这个标记的话,就会发生错误:
'𝒳'.match(/[𝒳-𝒴]/); // SyntaxError: invalid range in character class
这里的正则 [𝒳-𝒴]
可以看作 [12-34]
(2
是 𝒳
的右半部分,3
是 𝒴
的左半部分)。2
和 3
之间所代表的范围并不是可接受的。
当然使用标记的话就解决了这个问题:
alert( '𝒴'.match(/[𝒳-𝒵]/u) ); // 𝒴
最后,让我们注意到,如果我们无需处理代理对的话,/.../u
标记对我们没有任何作用。但在现代社会,我们经常遇到他们。
(完)