无法匹配示例表情符号。这可能是什么原因?

Unable to match a sample emoji. What could be the reason for this?

Miscellaneous Symbols and Pictographs 是一个 Unicode 块,包含气象和天文符号、主要用于与日本电话运营商的 Shift JIS 实现兼容的表情符号字符,以及最初来自 Microsoft [=22] 中的 Wingdings 和 Webdings 字体的字符=].

引用的维基百科文章指定的 Unicode 范围是 U+1F300..U+1F5FF

但是如果我从列表中选择一个表情符号并进行正则表达式匹配,它会失败。

var a = "";
var matched = a.match(/[\u1F300-\u1F5FF]/);

matched 始终为空。这是为什么?我哪里出错了?

问题

Javascript 有一段时间了 Unicode Problem。位于 U+0000...U+FFFF 范围之外的 Unicode 代码点被称为 astral 代码点,并且存在问题,因为它们不容易通过正则表达式匹配:

// `` is an astral symbol because its codepoint value
//  of U+1F30D is outside the range U+0000...U+FFFF
//  Astral symbols do not work with regular expressions as expected
var regex = /^[bc]$/;
console.log(
    regex.test('a'),  // false
    regex.test('b'),  // true
    regex.test('c'),  // true
    regex.test('')  // false (!)
);
console.log(''.match(regex)); // null (!)

原因是因为这个星体代码点实际上由两部分组成,或者更准确地说是由两个“代码单元”组成, 这两个代码单元组合在一起形成字符。

console.log("\u1F30D")      // Doesn't work
console.log("\uD83C\uDF0D") // 

星体符号实际上由两个编码单元组成:=U+D83C + U+DF0D!
所以如果你想匹配这个星体符号,你必须使用以下正则表达式和匹配器:

var regex = /^([bc]|\uD83C\uDF0D)$/;
console.log(
    regex.test('a'),  // false
    regex.test('b'),  // true
    regex.test('c'),  // true
    regex.test('\uD83C\uDF0D')  // true
);
console.log('\uD83C\uDF0D'.match(regex)); // { 0: "", 1: "", index: 0 ... }

所有星体符号都有这个分解。惊讶吗?好吧,也许你应该——这并不经常发生!它只发生在星体代码点很少使用。我自己和世界上其他人使用的大多数代码点都不是 astral——它们在 U+0000...U+FFFF 范围内——所以我们通常不会看到这个问题。表情符号是这一规则的新例外——所有表情符号都是星体符号,并且由于社交媒体,它们的使用在世界范围内变得越来越流行。

使用像这样的代码单元是 Unicode 的 实现细节 ,不幸的是 Javascript 程序员。它很容易给程序员造成混淆,因为不清楚是使用字符逐字 () 还是使用代码单元分解 (U+D83C + U+DF0D ) 每当使用 matchtest、... 等字符串函数时;或者每当使用正则表达式和字符串文字时。然而,语言设计者和实现者正在努力改进。

解决方案

最近添加到 ECMAScript 6 (ES6) 的是 introduction of a u flag 正则表达式匹配。这允许您按 codepoint 匹配,而不是按 code units(默认)匹配。

var regex = /^[bc]$/u; // <-- u flag added
console.log(
    regex.test('a'), // false
    regex.test('b'), // true
    regex.test('c'), // true
    regex.test('')  // true <-- it now works!
);

通过使用 u 标志,您不必担心您的代码点是否是 astral 代码点,也不必在代码单元之间进行转换。 u 标志使正则表达式以直观的方式工作——即使是表情符号!但是,并非 Node.js 的每个版本和每个浏览器都支持此新功能。要支持所有环境,您可以使用像 regenerate.

这样的库