当计数标志表情符号时,Swift countElements()返回不正确的值

ZYi*_*iOS 15 unicode ios emoji swift countelements

let str1 = ""
let str2 = "....."

println("\(countElements(str1)), \(countElements(str2))")
Run Code Online (Sandbox Code Playgroud)

结果:1,10

但是str1不应该有5个元素吗?

这个错误似乎只发生在我使用标志表情符号时.

Mar*_*n R 21

Swift 4更新(Xcode 9)

从Swift 4开始(使用Xcode 9 beta测试),按照Unicode 9标准的要求,每隔一个区域指示符号后,字形集群就会中断:

let str1 = ""
print(str1.count) // 5
print(Array(str1)) // ["", "", "", "", ""]
Run Code Online (Sandbox Code Playgroud)

也是String其角色的集合(再次),因此可以获得字符数str1.count.


(Swift 3及以上版本的旧答案:)

来自" 标准附件#29 UNICODE TEXT SEGMENTATION"中的"3 Grapheme Cluster Boundaries ":(重点补充):

遗留字形集群定义为基数(例如A或カ),后跟零个或多个连续字符.想到这一点的一种方法是形成"堆叠"的一系列字符.

基数可以是单个字符,也可以是形成韩语音节的任何Hangul Jamo字符序列,如Unicode标准中的D133所定义,或者是Regional_Indicator(RI)字符的任何序列.RI字符成对使用以表示对应于ISO国家代码的表情符号国旗符号.两个以上RI字符的序列应该用其他字符分隔,例如U + 200B ZWSP.

(感谢@rintaro的链接).

Swift Character表示扩展的字形集群,因此它(根据此参考)是正确的,任何区域指示符号序列都被计为单个字符.

您可以通过ZERO WIDTH NON-JOINER分隔"标志":

let str1 = "\u{200C}"
print(str1.characters.count) // 2
Run Code Online (Sandbox Code Playgroud)

或插入零宽度空间:

let str2 = "\u{200B}"
print(str2.characters.count) // 3
Run Code Online (Sandbox Code Playgroud)

这也解决了可能的歧义,例如应该""是""还是""?

另请参阅如何知道两个表情符号是否将显示为一个表情符号?关于一个可能的方法来计算一个Swift字符串中的"组合字符"的数量,这将返回5给你的let str1 = "".

  • 好抓!现在知道_why_他们这样设计它会很有趣,恕我直言,这是一个疣. (2认同)
  • 值得注意的是,从Unicode标准附件#29的Unicode 9.0.0和[版本29](http://www.unicode.org/reports/tr29/tr29-29.html)开始,规则已经改变.在一系列区域指标符号中,字素集群在每第二个区域指标符号后突破.我不知道Swift是否实施了新规则. (2认同)