UTF8字符串长度和Go vs Swift中的索引

时间:2018-05-02 14:24:12

标签: swift string go utf-8

我在Go和Swift中有应用程序处理字符串,例如查找子字符串及其索引。起初它甚至可以很好地使用多字节字符(例如表情符号),使用Go的utf8.RuneCountInString()和Swift的原生字符串。

但是有一些UTF8字符会破坏字符串长度和子字符串的索引,例如字符串"Lorem ✌️ ipsum"

Go {'1}}返回17,utf8.RuneCountInString("Lorem ✌️ ipsum")的起始索引为12。

Swift的ipsum返回16,"Lorem ✌️ ipsum".count的起始索引为11。

使用Swift String' ipsumutf8或转换为utf16也会提供不同的长度和索引。还有其他表情符号由多个其他表情符号组成,可以提供更有趣的数字。

这是Go 1.8和Swift 4.1。

有没有办法获得相同的字符串长度和子字符串'与Go和Swift具有相同值的索引?

修改

我根据@ MartinR的优秀答案创建了一个Swift String扩展:

NSString

2 个答案:

答案 0 :(得分:7)

在Swift中,Character是一个“扩展的字形集群”,每个“”,“”,“✌️”,“”,“”都算作单个字符。

我没有Go的经验,但据我所知Strings, bytes, runes and characters in Go, “符文”是一个Unicode代码点,它基本上对应于Swift中的UnicodeScalar

在你的例子中,区别来自“✌️” 算作单个Swift字符,但是由两个Unicode标量构建:

print("✌️".count) // 1
print("✌️".unicodeScalars.count) // 2

以下是如何计算长度和偏移量的示例 Unicode标量术语:

let s = "Lorem ✌️ ipsum"
print(s.unicodeScalars.count) // 17

if let idx = s.range(of: "ipsum") {
    print(s.unicodeScalars.distance(from: s.startIndex, to: idx.lowerBound)) // 12
}

如您所见,这与Go中的示例中的数字相同。

答案 1 :(得分:0)

A rune in Go identifies a specific UTF-8 code point;这并不一定意味着它将1:1映射到视觉上不同的字符。某些字符可能由多个符文/代码点组成,因此计数符文可能无法提供您对字符串的视觉检查所期望的内容。我不知道Swift中"some text".count实际上有多重要,所以我不能在那里提供任何比较。