t;];
//1. 默认排序方式
NSArray *defaultedSortedArray = [rawArray sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
return [obj1 compare:obj2 options:NSCaseInsensitiveSearch];
}];
__block NSMutableArray *codeUnits = [NSMutableArray array];
[defaultedSortedArray enumerateObjectsUsingBlock:^(NSString* _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[codeUnits addObject:@([obj characterAtIndex:0])];
}];
NSLog(@"默认Unicode码点值排序 %@ 对应的各个字符串的首字符码点值是 %@", [defaultedSortedArray descriptionWithLocale:cnLocal], codeUnits);
输出结果是
排序结果
.. 123 @ AA abb abc μ язык ? ? 一生一世 上 爱你
对应的各个字符串的首字符码点值是
46 49 64 65 97 97 956 1103 12928 12964 19968 19978 29233
我们常用的各种字符的码点值范围是:
- 0-9 U+0030 - U0039
- a-z U+0061 - U+007A
- A-Z U+0041 - U+005A 具体可通过:unicode-table查询。
UCA 默认排序
在我们前面下载的文件CLDR库有个/common/uca/allkeys_CLDR.txt文件,它表示我们指定locale为“en”或者说是默认的排序规则。它的格式是
0000 ; [.0000.0000.0000] # <NULL>
0001 ; [.0000.0000.0000] # <START OF HEADING>
0002 ; [.0000.0000.0000] # <START OF TEXT>
0003 ; [.0000.0000.0000] # <END OF TEXT>
分号前的值表示码点,分号后中括号里面的值表示UCA算法权重,用.
号来区分,Unicode字符就是按照这个规则从上到下排序。
NSLocale *enLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en"];
defaultedSortedArray = [rawArray sortedArrayUsingComparator:^NSComparisonResult(NSString* _Nonnull obj1, NSString* _Nonnull obj2) {
return [obj1 compare:obj2 options:0 range:NSMakeRange(0, obj1.length) locale:enLocale];
}];
NSLog(@"默认排序规则或者指定地区为locale后的排序结果是 %@", [defaultedSortedArray descriptionWithLocale:cnLocal]);
排序结果是
默认排序规则或者指定地区为en后的排序结果是
.. (ch (en @ 123 AA abb abc μ язык ? 一生一世 上 ? 爱你
这种排序依次为符号,数字,英文/汉字等script charaters。
CLDR调整后的排序
在下载的CLDR文件中,有个common/bcp47/collation.xml文件,列出了可选的排序方式,有standard,pinyin, stroke(笔画排序)等。
排序可选方式
那如何确定各个区域语言下,该使用哪种排序规则呢,我们可以看到common/collation/文件夹下,有很多标记语言LDML文件,这些文件就是表示在不同区域语言下,采用的排序规则。
我们打开zh.xml,这个就是我们简体中文的排序规则,可以看到,里面默认采用的排序是pinyin排序,并且在开头还写了各个声调字母的排序先后顺序。
- 首先按照pinyin声调的先后顺序进行排序,即zh.xml底下列出的先后顺序进行排序。
- 如果是在同一行的汉字,则按照笔画由少到多的顺序进行排序。
- 如果还不能区分大小,就按照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,和NSCaseInsen