objc系列译文(9.2):玩转字符串

在每个应用里我们都大量使用字符串。下面我们将快速看看一些常见的操作字符串的方法,过一遍常见操作的最佳实践。

字符串的比较、搜索和排序

排序和比较字符串比第一眼看上去要复杂得多。不只是因为字符串可以包含代理对(surrogate pairs )(详见 Ole 写的这篇关于 Unicode 的文章) ,而且比较还与字符串的本地化相关。在某些极端情况下相当棘手。

苹果文档中 String Programming Guide 里有一节叫做 “字符与字形集群(Characters and Grapheme Clusters)”,里面提到一些陷阱。例如对于排序来说,一些欧洲语言将序列“ch”当作单个字母。在一些语言里,“ä”被认为等同于 ‘a’ ,而在其它语言里它却被排在 ‘z’ 后面。

而 NSString 有一些方法来帮助我们处理这种复杂性。首先看下面的方法:

它带给我们充分的灵活性。另外,还有很多“便捷函数”都使用了这个方法。

与比较有关的可用参数如下:

它们都可以用逻辑或运算组合在一起。

NSCaseInsensitiveSearch :“A”等同于“a”,然而在某些地方还有更复杂的情况。例如,在德国,“ß” 和 “SS”是等价的。

NSLiteralSearch :Unicode 的点对 Unicode 点比较。它只在所有字符都用相同的方式组成的情况下才会返回相等。LATIN CAPITAL LETTER A 加上 COMBINING RING ABOVE 并不等同于 LATIN CAPITAL LETTER A WITH RING ABOVE.

译注:这个要解释一下,首先,每一个Unicode都是有官方名字的!LATIN CAPITAL LETTER A是一个大写“A”,COMBINING RING ABOVE是一个  ̊,LATIN CAPITAL LETTER A WITH RING ABOVE,这是Å前两者的组合不等同于后者。

NSNumericSearch:它对字符串里的数字排序,所以 “Section 9” < “Section 20” < “Section 100.”

NSDiacriticInsensitiveSearch : “A” 等同于 “Å” 等同于 “Ä.”

NSWidthInsensitiveSearch : 一些东亚文字(平假名 和 片假名)有全宽与半宽两种形式。

很值得一提的是 – (NSComparisonResult)localizedStandardCompare: ,它排序的方式和 Finder 一样。它对应的选项是 NSCaseInsensitiveSearch 、 NSNumericSearch 、NSWidthInsensitiveSearch 以及 NSForcedOrderingSearch 。如果我们要在UI上显示一个文件列表,用它就最合适不过了。

大小写不敏感的比较和音调符号不敏感的比较都是相对复杂和昂贵的操作。如果我们需要比较很多次字符串那这就会成为一个性能上的瓶颈(例如对一个大的数据集进行排序),一个常见的解决方法是同时存储原始字符串和折叠字符串。例如,我们的 Contact  类有一个正常的 name  属性,在内部它还有一个foldedName  属性,它将自动在 name变化时更新。那么我们就可以使用 NSLiteralSearch  来比较 name  的折叠版本。 NSString  有一个方法来创建折叠版本:

搜索

要在一个字符串中搜索子字符串,最灵活性的方法是:

同时,还有一些“便捷方法”,它们在最终都会调用上面这个方法,我们可以传入上面列出的参数,以及以下这些额外的参数:

NSBackwardsSearch :在字符串的末尾开始反向搜索。

NSAnchoredSearch : 只考虑搜索的起始点(单独使用)或终止点(当与 NSBackwardsSearch  结合使用时)。这个方法可以用来检查前缀或者后缀,以及大小写不敏感(case-insensitive)或者音调不敏感(diacritic-insensitive)的比较。

NSRegularExpressionSearch :使用正则表达式搜索,要了解更多与使用正则表达式有关的信息,请关注 Chris’s 的 String Parsing 。

另外,还有一个方法:

与前面搜索字符串不同的是, 它只搜索给定字符集的第一个字符。即使只搜索一个字符,但如果由于此字符是由元字符组成的序列(composed character sequence),所以返回范围的长度也可能大于1。

大写与小写

一定不要使用 NSString  的 -uppercaseString  或者 -lowercaseString  的方法来处理 UI 显示的字符串,而应该使用 -uppercaseStringWithLocale  来代替, 比如:

格式化字符串

同C语言中的 sprintf 函数( ANSI C89 中的一个函数 )类似, Objective C 中的 NSString 类也有如下的3个方法:

需要注意这些格式化方法都是 非本地化 的 。所以这些方法得到的字符串是不能直接拿来显示在用户界面上的。如果需要本地化,那我们需要使用下面这些方法:

Florian 有一篇关于 字符串的本地化 的文章更详细地讨论了这个问题。

printf(3)的man页面有关于它如何格式化字符串的全部细节。除了所谓的转换格式(它以%字符开始),格式化字符串会被逐字复制: