4

一般来说,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

斯威夫特将此组合视为两个字符!

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

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

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

在此处输入图像描述

4

1 回答 1

7

emrys57 的评论中提到的错误报告中给出了部分答案。在将 Unicode 字符串拆分为“字符”时,Swift 显然使用了UAX #29 Unicode Text Segmentation中定义的 Grapheme Cluster Boundaries 。区域指示符号之间有一条不中断的规则,但表情符号修饰符没有这样的规则。因此,根据 UAX #29,字符串"\u{1f6b4}\u{1f3fe}"包含两个字素簇。请参阅Unicode 邮件列表上来自 Ken Whistler 的此消息以获得解释:

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

于 2016-03-07T16:45:53.073 回答