【问题标题】:Why is Swift counting this Grapheme Cluster as two characters instead of one?为什么 Swift 将这个 Grapheme Cluster 计算为两个字符而不是一个字符?
【发布时间】:2016-06-19 19:33:44
【问题描述】:

一般而言,Swift 非常非常聪明地将字素簇计算为单个字符。例如,如果我想制作黎巴嫩国旗,我可以将两个 Unicode 字符组合起来

  • U+1F1F1 区域指标符号字母 L
  • U+1F1E7 区域指标符号字母 B

正如预期的那样,这是 Swift 中的一个字符:

let s = "\u{1f1f1}\u{1f1e7}"
assert(s.characters.count == 1)
assert(s.utf16.count == 4)
assert(s.utf8.count == 8)

但是,假设我想制作 Fitzpatrick Type-5 的自行车手表情符号。如果我结合

  • U+1F6B4 自行车手
  • U+1F3FE 表情修饰符 FITZPATRICK TYPE-5

Swift 将此组合计为 两个 个字符!

let s = "\u{1f6b4}\u{1f3fe}"
assert(s.characters.count == 2)   // <----- WHY?
assert(s.utf16.count == 4)
assert(s.utf8.count == 8)

为什么这是两个字符而不是一个?

为了说明为什么我期望它是 1,请注意这个集群实际上被解释为一个有效的表情符号:

【问题讨论】:

  • 这看起来像一个错误报告。为什么不把它发给 Swift 团队呢?
  • unicode.org/reports/tr51 有点含糊:“只要这些字符中的一个紧跟在某些字符(例如 WOMAN)之后,那么字体就应该将序列显示为单个字形......”
  • bugs.swift.org/browse/SR-375 讨论了这一点。不幸的是,这并不能说明情况。
  • 哇,我没有看到那个 Swift 错误报告!我可能应该有。

标签: swift unicode emoji grapheme


【解决方案1】:

emrys57 的评论中提到的bug report 给出了部分答案。在将 Unicode 字符串拆分为“字符”时,Swift 显然使用了 UAX #29 Unicode Text Segmentation 中定义的 Grapheme Cluster Boundaries。有一个rule not to break between regional indicator symbols,但表情符号修饰符没有这样的规则。因此,根据 UAX #29,字符串"\u{1f6b4}\u{1f3fe}" 包含两个字素簇。请参阅 Unicode 邮件列表中来自 Ken Whistler 的 this message 以获得解释:

这是因为修饰符的后备行为是 简单地作为独立的象形文字,即颜色样本图像。 [...] 您需要额外的、特定的 关于这些序列的知识——它不只是从一个 默认实现 UAX #29 用于字素集群的规则。

【讨论】:

    猜你喜欢
    • 2015-12-05
    • 1970-01-01
    • 2012-04-19
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-19
    • 1970-01-01
    相关资源
    最近更新 更多