【问题标题】:Unable to match a sample emoji. What could be the reason for this?无法匹配示例表情符号。这可能是什么原因?
【发布时间】:2017-12-19 13:58:36
【问题描述】:

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 始终为空。这是为什么?我在哪里做错了?

【问题讨论】:

  • JavaScript 字符串不支持真正的 Unicode,只支持 UCS-2。
  • 你不能像这样在 JavaScript 中使用 5 个字符的 Unicode 代码点。这实际上是匹配字符类\u1f30 或从0\u1f5f 或字符f 的任何内容。在 ECMAScript 6 中,您应该可以使用 [\u{1f300}-\u{1f5ff}]
  • 需要注意的是,当你对Unicode转义序列使用花括号形式时,需要将u标志传递给正则表达式,如:/[\u{1f300}-\u{1f5ff}]/u

标签: javascript string unicode emoji


【解决方案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 的范围内——所以我们通常不会看到这个问题。表情符号是这条规则的一个新例外 - 所有表情符号都是星体符号,并且由于社交媒体,它们的使用在世界范围内变得越来越流行。

使用像这样的代码单元是 Unicode 的一个实现细节,不幸的是它暴露给了 Javascript 程序员。由于不清楚是使用字符逐字(?)还是使用代码单元分解(U+D83C + U+DF0D ) 每当使用像 match, test, ... 这样的字符串函数时;或者每当使用正则表达式和字符串文字时。然而,语言设计者和实现者都在努力改进。

解决方案

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 标志,您不必担心您的代码点是否是星体代码点,也不必在代码单元之间进行转换。 u 标志使正则表达式以直观的方式工作 - 即使是表情符号!然而,并不是每个版本的 Node.js 和每个浏览器都支持这个新特性。要支持所有环境,您可以使用像 regenerate 这样的库。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-02
    • 1970-01-01
    相关资源
    最近更新 更多