深入理解苹果系统(Unicode)字符串的排序方法


引言:

在iOS中对列表数据进行按名称排序时,常常使用localizedStandardCompare:这个方法,这个方法是苹果推荐的用于排序的方法,但是这个方法背后的实现原理是什么很少有说到,本文就对该方法和背后的Unicode排序进行介绍,让大家更加明白在其他系统中也类似的排序原理。


Unicode编码

我们知道计算机是不能直接处理文本的,而是和数字打交道。因此,为了表示文本,就建立了一个字符到数字的映射表,叫做编码。最著名的字符编码就是ASCII了,它使用7-bit来表示应用字母表以及数字和其他字符。这对于英语来说是够用了,但是对于其他语言,这个7-bit就不能满足条件了,因为字符远远超过了7-bit所能表示的最大个数。因此1987年,来自几个大的科技公司的工程师开始合作开发一种致力于能在全世界的所有书写系统中都能通用的字符编码系统,并与1991年10发布了Unicode的1.0.0标准。2018年6月发布了Unicode的11.0版本。这里就不再对Unicode做过多的介绍,值得注意的是,在iOS开发中,常使用的的NSString是基于Unicode-16来开发的,这是因为当时开发这个的时候Unicode标准还是以16bit固定长度来编码,这就导致使用上的一些坑,建议大家阅读下这篇文章:NSString and Unicode

#UCA和CLDR:最常用到的排序标准

介绍完Unicode编码之后,我们就可以来介绍UCA(Unicode Collation Algorithm)和CLDR(Common Locale Data Repository)了,因为苹果的NSString的介绍文档里有这么一句话:

Localized string comparisons are based on the Unicode Collation Algorithm, as tailored for different languages by CLDR (Common Locale Data Repository). Both are projects of the Unicode Consortium. Unicode is a registered trademark of Unicode, Inc.

说白了,苹果系统的NSString字符串排序是基于UCA的,并且在不同语言下,经过CLDR来裁剪的。

UCA(Unicode Collation Algorithm)

UCA的介绍官方文档介绍在这里:UCA介绍。其中第一句话就写的很清楚,

Collation is the general term for the process and function of determining the sorting order of strings of characters.

对字符串排序的过程就是Collation,UCA就是Unicode表示的字符串进行排序的规则,制定这个规则的原因是不同语种对字符串的排序规则要求是不一样的,比如,德国、法国和瑞士对相同的字符排序的规则是不一样的,甚至在同一个语言下比如中文,多音字这种在不同组合里,排序的先后顺序也是不一样的。

我们打开zh.xml,这个就是我们简体中文的排序规则,可以看到,里面默认采用的排序是pinyin排序,并且在开头还写了各个声调字母的排序先后顺序。

  1. 首先按照pinyin声调的先后顺序进行排序,即zh.xml底下列出的先后顺序进行排序。
  2. 如果是在同一行的汉字,则按照笔画由少到多的顺序进行排序。
  3. 如果还不能区分大小,就按照kRSUnicode (偏旁索引的方式,按照康熙字典的定义)的先后顺序进行排序。

假如我们指定区域为zh_CN,则对于字符串中出现的中文则排在其他语言字符串前面。其他script charater则按照allkeys_CLDR.txt的顺序进行进行排序。值得注意的是,中文由于多音字,在这里不一定能够完全按照我们的习惯排序正确,比如“重逢(chong feng)”就没有第一个拼音chong去排,而是按照zhong来排列的。

默认排序规则或者指定地区为zh_CN后的排序结果是 
 ..  (ch  (en  @  0124  123  艾你  爱你  産  上  ㊤  ㊀  一生一世  重逢  重要  aa  AA  abb  μ  язык 
 
 默认排序规则或者指定地区为ru_CN后的排序结果是 
 ..  (ch  (en  @  0124  123  язык  aa  AA  abb  μ  ㊀  一生一世  上  ㊤  爱你  産  艾你  重要  重逢 
 

至此,我们大致讲清楚了几种排序规则。

苹果系统的排序

前面我们已经说了,苹果系统的NSString排序是UCA和CLDR规则的。NSString提供了很多的排序方法,但最终,所有的都是调用了compare:options:range:locale:来进行处理,只是传入的参数不同。可以在NSString.swift 中查看具体的实现。这么多排序方法中,其中之一是localizedStandardCompare:, 这个方法是苹果系统推荐的,在给用户展示的列表数据的名字或者其他字符串进行排序时所使用的方法。我们看到,它的内部实现是

   public func localizedStandardCompare(_ string: String) -> ComparisonResult {
        return compare(string, options: [.caseInsensitive, .numeric, .widthInsensitive, .forcedOrdering], range: NSRange(location: 0, length: length), locale: Locale.current._bridgeToObjectiveC())
    }

其中用到的四个Options参数是

NSCaseInsensitiveSearch  //大小写不敏感
NSNumericSearch //对字符串中出现的数字字符进行数字化的大小比较,比如Foo2.txt < Foo7.txt < Foo25.txt
NSWidthInsensitiveSearch //忽略宽度,按照实际表示的意思来对比,如'a' = UFF41
NSForcedOrderingSearch //强制返回Ascending或者Descending,和NSCaseInsensitiveSearch结合起来就是例如"aaa" > "AAA"

并且指定了当前的区域locale作为参数,这就相当于指定使用CLDR进行排序,如果是在手机上,这个方法的调用和系统当前的区域设置是有很大关系的,这和我们代码中设置locale是一个道理。我们可以这样理解,调用这个方法得到的结果和在iOS Files中文件名选择按照名称排序得到的结果是一样的。在iOS中,当我们的区域设置为中国时,排序顺序就是 标点符号等特殊符号>数字>中文>英文等其他

综述

本文主要讲述由localizedStandardCompare:这个苹果系统方法所引发的对排序规则的深入研究,简单来说,设置中选择区域为中国时,排序顺序为 标点符号等特殊符号>数字>中文>英文等其他。中文本身是按照pinyin排序的,只是由于多音字的关系,不能够做到100%按照中文习惯来排序,会有些无法正确排序的问题,但大体已经符合我们的习惯了。

参考

https://zh.wikipedia.org/wiki/Unicode

https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFStrings/Articles/UnicodeBasis.html

https://www.objc.io/issues/9-strings/unicode/

http://unicode.org/reports/tr10/

https://www.cnblogs.com/huahuahu/p/Unicode-zi-fu-chuan-pai-xu-gui-ze-yi-ru-he-que-din.html

https://raw.githubusercontent.com/larvit/larvitgeodata/master/cldrData/common/uca/allkeys_CLDR.txt

http://cldr.unicode.org/

本站文章资源均来源自网络,除非特别声明,否则均不代表站方观点,并仅供查阅,不作为任何参考依据!
如有侵权请及时跟我们联系,本站将及时删除!
如遇版权问题,请查看 本站版权声明
THE END
分享
二维码
海报
深入理解苹果系统(Unicode)字符串的排序方法
本文主要讲述下载苹果系统-方法所引发的对排序规则的深入研究。
<<上一篇
下一篇>>