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

时间:2017-07-14 12:49:01

标签: javascript string unicode emoji

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

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

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

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

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

1 个答案:

答案 0 :(得分:1)

问题

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

// `` 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 ... }

所有星号符号都有此分解。惊讶吗?也许你应该 - 这不经常发生!它只发生在星际代码点 很少使用。我和世界各地的其他人使用的大多数代码点都不是星号 - 它们在U + 0000 ... U + FFFF范围内 - 所以我们通常不会看到这个问题。 Emojis是这个规则的新例外 - 所有表情符号都是星体符号,并且由于社交媒体,它们的使用在全世界越来越受欢迎。

使用像这样的代码单元是Unicode的实现细节,不幸的是暴露给Javascript程序员。它很容易引起程序员的困惑,因为不清楚是使用字符verbatim()还是使用代码单元分解( U + D83C + U + DF0D )每当使用matchtest,...之类的字符串函数时;或者每当使用正则表达式和字符串文字时。然而,语言设计师和实施者并努力改进事物。

解决方案

ECMAScript 6(ES6)的最新成员是introduction of a u flag到正则表达式匹配。这允许您通过代码点匹配,而不是通过代码单元匹配(默认)。

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标记,您不必担心您的代码点是否是星号代码点,并且您不必转换代码单元和从代码单元转换。 u标志使正则表达式以直观的方式工作 - 即使对于表情符号!但是,并非每个版本的Node.js都支持这一新功能。要支持所有环境,您可以使用regenerate等库。