使用Locale.SIMPLIFIED_CHINESE和Collator进行排序时出现错误排序

12

我正在尝试使用Locale.SIMPLIFIED_CHINESE按国家名称排序,但它似乎是使用拼音(即根据字符的拉丁字母组合进行排序,从A到Z)。

但我发现有些情况下排序不正确。例如:

  • '中' 字符应为 zhong1
  • '梵' 字符应为 fan4

正确的顺序应该是 梵 < 中 ,但实际上排序方式相反。

String[] characters = new String[] {"梵", "中"};
List<String> list = Arrays.asList(characters);
System.out.println("Before sorting...");
System.out.println(list.toString());

Collator collator = Collator.getInstance(Locale.SIMPLIFIED_CHINESE);
collator.setStrength(Collator.PRIMARY);
Collections.sort(list, collator);

System.out.println("After sorting...");
System.out.println(list.toString());

这段代码的结果是:

Before sorting...
[梵, 中]
After sorting...
[中, 梵]

深入了解后,我发现Java在Locale.SIMPLIFIED_CHINESE下应用的排序规则。您可以在以下图像中找到:

https://postimg.cc/image/4t915a7gp/full/(请注意,梵字在中文之后)。

我注意到,在我用红色标出的<口<口<口<口<口之前,所有字符都按照它们的拉丁字母对应组合顺序排列,从A到Z。然而,在<口<口<口<口<口符号之后,字符按其组成进行排序。例如,如果所有字符具有相同的部分(通常是字符的左部),则它们会被分组在一起,而不是按照A到Z的顺序排列。

此外,<口<口<口<口<口之后的所有字符都是较不常见的中国汉字。因此,梵字比中字更不常见,所以它放置在<口<口<口<口<口之后。

我想知道为什么会做出这个决定,是否是故意的。但它会导致错误的排序。我不知道如何解决这个问题。


你尝试过使用icu4j吗? - fge
我已经尝试了pinyin4j,他们的排序很好。icu4j还没有尝试过。但我的问题是关于为什么Oracle使用那些规则进行排序,也许这是一个需要报告的错误,或者也许有另一种使用Java API按拼音惯例排序的方法。在我们公司中,由于可靠性的原因,很难添加新的库。感谢您的支持! - elegarpes
1个回答

2
Java中提供的排序顺序是基于书写该字符所需笔画的。请看下面的小片段进行演示。笔画数字取自Wikitionary
// the unicode character and the number of strokes
String[] characters = new String[]{
    "\u68B5 (11)", "\u4E2D (4)", 
    "\u5207 (4)", "\u5973 (3)", "\u898B (7)"
};
List<String> list = Arrays.asList(characters);
System.out.println("Before sorting...");
System.out.println(list.toString());

Collator collator = Collator.getInstance(Locale.TRADITIONAL_CHINESE);
collator.setStrength(Collator.PRIMARY);
System.out.println();
Collections.sort(list, collator);

System.out.println("After sorting...");
System.out.println(list.toString());

输出

Before sorting...
[梵 (11), 中 (4), 切 (4), 女 (3), 見 (7)]

After sorting...
[女 (3), 中 (4), 切 (4), 見 (7), 梵 (11)]

有一个增强请求JDK-6415666,要求根据Unicode排序顺序实现排序顺序。但是根据Java 8支持的语言环境的信息,在Java 8中未实现此功能。 编辑 使用icu4j中的排序器进行排序。
[梵 (11), 見 (7), 女 (3), 切 (4), 中 (4)]

ICU4J 代码片段

import com.ibm.icu.text.Collator;
import com.ibm.icu.text.RuleBasedCollator
...
Locale locale = new Locale("zh", "", "PINYIN");
Collator collator = (RuleBasedCollator) Collator.getInstance(locale);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接