使用 Java Collat​​or 区分大小写的顺序

Posted

技术标签:

【中文标题】使用 Java Collat​​or 区分大小写的顺序【英文标题】:Case sensitive order using Java Collator 【发布时间】:2013-09-16 15:36:39 【问题描述】:

我试图了解使用Java Collator 时区分大小写的顺序应该如何真正起作用。

在this example 中,以下字符串在法语语言环境中使用所有优势进行排序(出于说明目的,我在数据集中添加了一些额外的字符串):

[Äbc, äbc, Àbc, àbc, Abc, abc, ABC] - Original Data
[Äbc, äbc, Àbc, àbc, Abc, abc, ABC] Primary
[Abc, abc, ABC, Àbc, àbc, Äbc, äbc] Secondary
[abc, Abc, ABC, àbc, Àbc, äbc, Äbc] Tertiary

Case kicks in only with Tertiary Collation Strength  : 
[CACHE, cache, Cache, da, DA, Da] - Original Data
[CACHE, cache, Cache, da, DA, Da] Primary
[CACHE, cache, Cache, da, DA, Da] Secondary
[cache, Cache, CACHE, da, Da, DA] Tertiary

但我真正期待的结果是这样的:

[abc, àbc, äbc, Abc, ABC, Àbc, Äbc] Tertiary
[cache, da, Cache, CACHE, Da, DA] Tertiary

换句话说,我希望所有小写字母都在前面(按字母顺序排序),然后是大写字母(反之亦然)。这不是一个合理的期望吗?

【问题讨论】:

我不明白你的疑问。您希望 Collat​​or 在设计上表现得与众不同,还是结果让您大吃一惊? 我想得到不同的结果,并且对我得到的任何结果感到惊讶。所以我的问题是——如果这是设计使然,如果是的话——如何实现我想要的? well String compareTo 默认使用字典顺序。 docs.oracle.com/javase/6/docs/api/java/lang/…你想要不同的东西吗? compareTo 不是很有用,因为它不会在本地化上下文中对字符串进行排序,而是按照 Unicode 中定义的顺序进行排序。我需要在任意语言环境中订购文本。 如果您的语言环境包括真正的 ä 和变音符号,我会使用带有语言环境的 Collat​​or 加上 FULL_DECOMPOSITION。不幸的是,我现在不能尝试,但我认为你会像这样实现你的目标。我将您的问题添加为书签,以便进行更精确的分析。 【参考方案1】:

有趣的是,android javadoc 比 oracle 更有用 - 特别是:

当字符串中的任何位置存在主要或次要差异时,忽略三次差异。

另外值得注意的是:您获得的顺序是您在法语语言环境中所期望的。根据wikipedia article on "ordre alphabétique":

En première analysis, les caractères accentués, de meme que les majuscules, ont le meme rang alphabétique que le caractère fundamental。 Si plusieurs mots ont le même rang alphabétique, on tâche de les distinguer entre eux grâce aux majuscules et aux 口音(pour le e, on a l'ordre e, é, è, ê, ë)

英文(我用斜体添加):

第一步包括对字母进行排序,无论它们的重音或大小写如何(即:a、A、à 排名相同)。如果在第一步之后多个单词具有相同的排名,则将考虑大小写和重读。

换句话说,c(小型股)和D(大型股)始终可以按主要强度排序,而第三次强度不会改变该顺序。

因此,在您的示例中,无论大小写和重音如何,cache 始终位于 da 之前。仅当主字母相同时,大小写才会有所不同(例如c(小)与C(大))。

【讨论】:

感谢您的回答。我不会说法语,也无法真正评论这个要求是否强烈以及它出现在什么上下文中,但在我的母语中没有这样的要求,但我得到的结果与法语相同。我的主要观点是人们习惯了这种大写字母在小写字母之前的排序,主要是因为historical reasons。它在其他编程语言中如何工作?也很奇怪,互联网在这个问题上神秘地保持沉默。 @mindas:排序是关于人类语言顺序而不是技术 ASCII 顺序。使用整理器是反对字典(ASCII 或 Unicode)排序的有意识决定。 @mindas 我想说的是(a)它的工作原理与宣传的一样,(b)它恰好是正确的字母顺序(您在字典中找到的顺序)法语。【参考方案2】:

示例代码按预期工作。您可以使用自定义排序规则来获得所需的输出。

RuleBasedCollator 是 JDK 中 Collat​​or 的唯一子类。您对 Collat​​or.getInstance(Locale.FRANCE) 的调用会返回 RuleBasedCollat​​or 的实例

您可以使用

创建自己的实例
RuleBasedCollator myCollator = new RuleBasedCollator(rules);

规则的格式在javadoc 中给出。

希望对你有帮助。

【讨论】:

【参考方案3】:

您不应该对区域设置敏感的整理器的排序结果做出假设。

这并不是为了反映 ASCII 顺序等技术方面,而是反映人类语言规则,例如就像人们对图书馆中的书名或电话簿中的姓名进行排序一样。通常,您不会找到将大写书架与小写书架分开的书架。

为了说明更令人惊讶的行为,请看以下示例:

String s1="IDONTCARE", s2="idontcare";
System.out.println("Comparing '"+s1+"' and '"+s2+"' locale sensitive");
Locale[] all= Locale.ENGLISH, new Locale("tr") ;
for(Locale l:all)

  System.out.println();
  System.out.println(l);
  Collator c1=Collator.getInstance(l);
  c1.setStrength(Collator.PRIMARY);
  System.out.println("primary:\t"+c1.compare(s1, s2));
  c1.setStrength(Collator.SECONDARY);
  System.out.println("secondary:\t"+c1.compare(s1, s2));
  c1.setStrength(Collator.TERTIARY);
  System.out.println("tertiary:\t"+c1.compare(s1, s2));
  c1.setStrength(Collator.IDENTICAL);
  System.out.println("identical:\t"+c1.compare(s1, s2));

它将打印:

Comparing 'IDONTCARE' and 'idontcare' locale sensitive

en
primary:    0
secondary:  0
tertiary:   1
identical:  1

tr
primary:    -1
secondary:  -1
tertiary:   -1
identical:  -1

如前所述,不要期望知道结果而忘记带有整理器的 ASCII/Unicode 字典顺序。

【讨论】:

【参考方案4】:

另一种选择:如果您需要自定义语言环境的规则,可以尝试使用 RuleBasedCollat​​or:

    RuleBasedCollator collTemp = (RuleBasedCollator) Collator.getInstance(Locale.US);

    String usRules = collTemp.getRules();

    //Remove dashes rule from US locale (dashes come after letters)
    usRules = usRules.replace(",'-'", "");

    //Create a collator with customized rules    
    RuleBasedCollator coll = new RuleBasedCollator(usRules);

    //Sort the collection based on collator
    Collections.sort(lines, coll);

【讨论】:

以上是关于使用 Java Collat​​or 区分大小写的顺序的主要内容,如果未能解决你的问题,请参考以下文章

使用 collat​​e nocase 字段的 SQLite 区分大小写搜索

HuggingFace:使用自定义 data_loader 和 data_collat​​or 从本地目录流式传输数据集

序列化 Collat​​or 实例

javascript INTL-collat​​or.js

LIKE运算符是否与MSSQL Server区分大小写?

局部匹配忽略案例和变音符号