String.count vs NSString.length

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

String.count

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

比如:

Note that Swift’s use of extended grapheme clusters for <span class="pre">Character</span> values means that string concatenation and modification may not always affect a string’s character count.

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

NSString.length

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

兼容性

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

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

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

Swift 里的 UTF16 字符串长度

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

讨论

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

转载请保留出处和原文链接:https://www.logcg.com/archives/3253.html

About the Author

R0uter

如非声明,本人所著文章均为原创手打,转载请注明本页面链接和我的名字。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注