Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios NSString localizedCompare:给定更长字符串的结果不一致_Ios_Cocoa_Core Data_Unicode_Localization - Fatal编程技术网

Ios NSString localizedCompare:给定更长字符串的结果不一致

Ios NSString localizedCompare:给定更长字符串的结果不一致,ios,cocoa,core-data,unicode,localization,Ios,Cocoa,Core Data,Unicode,Localization,我们正在尝试使用NSFetchedResultsController返回人名,并使用localizedCompare:按排序顺序填充UITableView。我们还试图在UI中提供一个节索引(每个节的第一个字符的右列)。我们为NSFetchedResultsController提供了实体上的选择器,该选择器提供了每个实体应属于的部分(特别是人名的第一个字符,大写) 在处理使用Unicode代码点的人名时,我们遇到了一个问题NSFetchedResultsController抱怨实体未按节排序 具体

我们正在尝试使用
NSFetchedResultsController
返回人名,并使用
localizedCompare:
按排序顺序填充
UITableView
。我们还试图在UI中提供一个节索引(每个节的第一个字符的右列)。我们为
NSFetchedResultsController
提供了实体上的选择器,该选择器提供了每个实体应属于的部分(特别是人名的第一个字符,大写)

在处理使用Unicode代码点的人名时,我们遇到了一个问题
NSFetchedResultsController
抱怨实体未按节排序

具体而言:

reason=The fetched object at index 103 has an out of order section name 'Ø. Objects must be sorted by section name'}, {
reason = "The fetched object at index 103 has an out of order section name '\U00d8. Objects must be sorted by section name'";
问题似乎在于,
localizedCompare:
返回的比较值对于整个“单词”和前导字符是不同的

以下测试通过了,尽管我希望(“Ø”和“O”)与(“Østerhus”和“Osypowicz”)之间的比较结果一致

-(无效)testLocalizedSortOrder300
{
NSString*str1=@“Osowski”;
NSString*str2=@“Østerhus”;
NSString*str3=@“Osypowicz”;
NSString*字母1=@“O”;
NSString*字母2=@“Ø”;
//本地化比较:
//“奥索斯基”
nsComparisonRes=[str1本地化比较:str2];
xctasertrue(res==sensorderedscending,@“(localizedCompare:)预期“@”和“@”将被sensorderedscending,但得到%@”,str1,str2,res==sensorderedName?@“sensorderedName”:“sensorderedscending”);
//Østerhus<“Osypowicz”
res=[str2本地化比较:str3];
xctasertrue(res==sensorderedescing,@“(localizedCompare:)预期“@”和“@”将被sensorderedescing,但得到了%@”、str2、str3、res==sensorderedName?@“sensorderedName”:“sensorderedescing”);
//“O”<“Ø”
res=[字母1本地化比较:字母2];
XCTAssertTrue(res==sensorderedescending,@“(本地化比较:)预期“@”和“@”将被sensorderedescending,但得到%@”,字母1,字母2,res==sensorderedName?@“sensorderedName”:“sensorderedescending”);
}
因此,最终的问题是,给定一个使用Unicode代码点的人名(或任何其他字符串),我们如何正确地(以本地化的方式)返回与
localizedCompare:
指定的排序顺序相对应的节名


此外,
localizedCompare:
在后面加上其他字符时,显然将“Ø”和“O”视为
OrderedName

我希望
localizedCompare:
使用了导致这种行为的
NSStringCompareOptions
标志的特定组合。

通过使用
compare:options:
并启用
NSDiacriticInsensitiveSearch
,您可能会得到想要的结果

为了生成节索引,最好先去掉所有扩展字符的值,然后取第一个字母。比如:

[[str1 stringByFoldingWithOptions:NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch] substringToIndex:1]

这样一来,以重音字母开头的名字,如“埃瓦德”,在你取第一个字母之前,会被转换成“爱德华”。

是的,去过那里。我找到的唯一解决方案是为搜索创建第二个字段,简化字符(不要立即记住方法),并将其存储为用于搜索的第二个字段。虽然不是很优雅,但很管用

最终解决这个问题的方法是在数据库中存储规范化的节名

@马丁纳建议,让我看看这篇文章讨论了这种方法,是解决这个问题的关键时刻

虽然这并不能解释本地化比较的愚蠢行为:显然将“Ø”和“O”视为附加字符,但在我们的测试中,IMHO是一个更健壮、更完整的解决方案,适用于所有Unicode代码点

具体而言,方法是:

  • 在实体上创建(或利用现有)字段以接收实体的规范化节名(我们称之为
    sectionName
  • 首先,根据需要(例如,当人名更改时),使用规范化的节名*填充此字段(
    sectionName
  • 将此节名字段(
    sectionName
    )用于
    NSFetchedResultsController
    -initWithFetchRequest:managedObjectContext:sectionNameKeyPath:cacheName:的
    sectionNameKeyPath
    )的
  • 对于传递给
    NSFetchedResultsController
    的获取请求所使用的排序描述符,请确保首先按节名排序,然后按节内容的排序方式(例如人名)排序,注意使用本地化版本的比较选择器。e、 g:

    [NSSortDescriptor sortDescriptorWithKey:@"sectionName" ascending:YES selector:@selector(localizedStandardCompare:)],
    [NSSortDescriptor sortDescriptorWithKey:@"personName" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)]
    
  • 测试

  • *规范化节名

    在处理unicode时,我们需要小心假设第一个“字符”是什么。“字符”可以由多个字符组成。 看见 而且

    这是我用来生成规范化节名的方向:

        NSString *decomposedString = name.decomposedStringWithCanonicalMapping;
        NSRange firstCharRange = [decomposedString rangeOfComposedCharacterSequenceAtIndex:0];
        NSString *firstChar = [decomposedString substringWithRange:firstCharRange];
        retVal = [firstChar localizedUppercaseString];
    

    希望这种方法对其他人来说是清晰和有用的,谢谢大家的帮助。

    语言环境设置是什么?我很难重现这个问题。@MartinR“en_US”这似乎是一个类似的问题,也许其中一个答案有帮助。谢谢@a-goodale。遗憾的是,我们不能使用
    compare:options:
    或类似选项。我们有SQLite商店作为后盾,所以我们的选择是有限的。特别是“SQLite支持的排序选择器有compare:和caseInsensitiveCompare:、localizedCompare:、localizedCaseInsensitiveCompare:、localizedCaseInsensitiveCompare:、和localizedStandardCompare:。后者是类似查找器的排序,大多数人在大多数情况下都应该使用。此外,不能使用SQLite存储对临时属性进行排序。”类似地,请参见
    stringBy
    
        NSString *decomposedString = name.decomposedStringWithCanonicalMapping;
        NSRange firstCharRange = [decomposedString rangeOfComposedCharacterSequenceAtIndex:0];
        NSString *firstChar = [decomposedString substringWithRange:firstCharRange];
        retVal = [firstChar localizedUppercaseString];