可搜索,可注册,可登录,致敬逗比大佬!尽在救援版逗比根据地 dbgjd.com
投稿文章 | 广告合作 | Telegram 群组 / 公告频道 / 使用教程

String.count vs NSString.length

News 转载自https://www.logcg.com 99℃ 0评论
最近更新:27th 八月, 2019

通常来讲,Swift 里的 String  是和 NSString  桥接的,比如我曾写过 NSString 和 String 究竟 有什么区别 ?,总之这里我们主要来讨论一下,Stringcount  和 NSStringlength  到底有什么区别。

String.count

String.count  实际上是 String.Characters.count  (Swift 早期版本),Swift 里的 String ,早期 count  属性就是单纯的字符数量,这和 NSString  是一样的,但很快就加入了扩展字形集群特性,比如一个 Emoji 表情,它的编码长度是普通字符的两倍,但这是视觉上的【一个】字符,于是它在 String  里算【一个】字符。

比如:

1
2
3
4
5
let s = “🐶”
 
print(s.count)
 
// result is 1

Note that Swift’s use of extended grapheme clusters for Character values means that string concatenation and modification may not always affect a string’s character count.

注意 Swift 为 Character 值使用的扩展字形集群意味着字符串的创建和修改可能不会总是影响字符串的字符统计数。

NSString.length

对于很有历史感的 NSString  来说,就没那么复杂了,它就是字符的数组,所以它只会单纯计算字符数量,由于一个 Emoji 就是用两个字符的长度表达的,所以在这里,长度为 2 :

1
2
3
4
5
let s = “🐶”
 
print((s as NSString).length)
 
//result is 2

兼容性

如果不注意这个问题,就会遇到很多奇怪的小错误,比如在设定富文本颜色的时候,会导致文本末尾异常,会导致 Emoji 乱码等等。因为富文本是 NSAttributedString ,它的长度计算是基于 UTF16 字符长度的,而不是合并后的【视觉】字符长度:

1
2
3
4
5
6
7
8
9
10
let s = “🐶”
 
let att = NSMutableAttributedString(string: s)
att.addAttributes([.foregroundColor:NSColor.red], range: NSRange(location: 0, length: s.count))
print(att)
 
// result is: �{
    NSColor = “sRGB IEC61966-2.1 colorspace 1 0 0 1”;
}{
}

注意高亮行,这里 NSRange(location: 0, length: s.count)  使用了 String  的 count  属性,读出的长度应该是 1 ,但 NSMutableAttributedString  是以 UTF16 字符长度做计算,所以字符串长度应该是 2 ,结果导致为半个 Emoji 字符添加颜色,输出内容为乱码。

1
2
3
4
5
6
7
8
9
let s = “🐶”
 
let att = NSMutableAttributedString(string: s)
att.addAttributes([.foregroundColor:NSColor.red], range: NSRange(location: 0, length: (s as NSString).length))
print(att)
 
//result is: 🐶{
    NSColor = “sRGB IEC61966-2.1 colorspace 1 0 0 1”;
}

将字符串转换为 NSString  后获取 length  则得到了正确结果。

Swift 里的 UTF16 字符串长度

那么,每次使用,都要明显地写成 (“” as NSString).length  的形式吗?虽然写个 extension  也不是不行,不过,我们其实也可以直接从 String  原生地获取这个长度:

1
2
3
4
5
let s = “🐶”
 
print(s.utf16.count)
 
//result is 2

讨论

StringNSString 有很多名称类似但功能相同的方法,但得到的结果却可能并不完全一致,要小心 Swift 对字符串的处理,这些问题往往会在一些细节的地方体现出来,比如输入法移动光标的 API,其中移动 1  长度,是 1  UTF16 字符长度,比如 Emoji,计数是 2 而不是 1,如果不注意这个细节,就会导致一些自动化功能在遇到 Emoji 表情或者某些生僻中文字符时计算出错,因为这些符号视觉上是一个字,但实际上使用了可变长的多个 UTF16 字符长度。

 

延伸阅读

https://stackoverflow.com/a/36268059

https://stackoverflow.com/a/29833042

https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html

https://www.cnswift.org/strings-and-characters

转载请注明:逗比根据地 » String.count vs NSString.length

喜欢 (0)
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址