在Java中对多语言环境字符串进行排序

时间:2010-11-17 10:04:22

标签: java sorting unicode localization

我正在尝试按字符串字段“country”对对象列表进行排序。每个国家都使用其母语

  • 阿根廷
  • 澳大利亚
  • Österreich
  • Ελλάδα
  • България...

我想要做的是例如“България”出现在“A *”国家之后,因为字母“Б”对应于拉丁语“B”。我正在尝试使用默认的Collat​​er,但非拉丁名称仍然列在最后列表中。

到目前为止,这是我的代码:

private static final Comparator<DomainTO> DOMAIN_COUNTRY_COMPARATOR =
    new Comparator<DomainTO>() {
    @Override
    public int compare(DomainTO t, DomainTO t1) {
        Collator defaultCollator = Collator.getInstance();
        return defaultCollator.compare(t.getCountry(), t1.getCountry());
    }
};

2 个答案:

答案 0 :(得分:34)

如何对来自不同语言的单词进行排序?有许多字母表(英语,俄语,德语等)。 每个人都订购了一系列信件。对来自一个字母表的单词进行排序很容易。但是有可能将所有这些字母合并成一个吗? 我认为不可能以一种可以被所有人接受的方式来实现。以英语和俄语字母为例。 俄语字母可以转换成英文字母(至少大部分都是这样)但是在这个演员之后他们会改变顺序。 这将有利于一个字母表而不是另一个字母表。为什么不给俄语写英文字母?
另一个问题是有特殊字母。在德语中,O和P之间有Ö,波兰语中有Ó在这个地方。 所以我们有以下关系:

O < Ö < P  
O < Ó < P

但是Ö和Ó之间的关系是什么?如果有一个国家Ósterreich它应该是或Österreich之后? 因此,不可能定义从不同语言中排序单词的通用规则。

我们所能做的就是将所有字母表投射到所选字母表中。这就是OP正在努力做的事 所选择的是拉丁字母,其他字母必须输入到这个字母表中。 问题是这种铸造通常是模棱两可的。很容易我们只能投出大部分俄语或希腊语字母 更大的问题是阿拉伯语或亚洲语言。我们应该记住,当从一个字母表转换到另一个字母表时,我们经常会丢失一些

那么我们怎么做这样的排序呢?

  1. 第一个主张是为每个国家手动提供拉丁名称。所以我们会有一个包含对的列表
    • РоссияRossija
    • ΕλλάδαEllada
      然后我们可以按拉丁名称和显示名称排序。
  2. 第二种方法是运行与此类似的代码:
  3. 代码:

    char [] russian = "АаБбВвГгДдЕеЁёЖжЗзИиЙйКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщ".toCharArray();  
    char [] russian_to = "AaBbWwGgDdEeEeZzZzIiJjKkLlMmNnOoPpRrSsTtUuFfHhCcCcSsss".toCharArray();  
    for (int i = 0; i < russian.length; i++) {
        input = input.replace(russian[i], russian_to[i]);
    }
    

    这样我们就转换了俄语字母表中的所有字母。现在我们必须为其他字母添加类似的代码。而俄语是最简单的 但是假设我们成功了,我们设法对世界上所有语言进行了这样的排序 但是进行这种分类的后果是什么?在我们回答这个问题之前,让我们问一下这样做的目的是什么。 OP没有说出他做这种排序的原因。但我们可以推断它:

    • 为什么我们要对元素进行排序?:为了使它们更容易找到。
    • 为什么国家/地区的名称是用母语?为了使这个列表对世界上只懂母语的公民有用。

    让我们回答这个问题:这种排序是否更容易找到只知道他母语的人的特定国家?

    1. 如果有人来自奥地利,那么他认为Österreich将在所有以O开头的国家之后。 但正常化后,Österreich将成为Osterreich,将介于安大略省和渥太华之间。 (我知道安大略省和渥太华不是国家。这只是一个例子)。
    2. 如果有人来自日本并且不懂拉丁字母,那么这种分类对他来说是没用的。他必须扫描所有名单,直到找到他的国家。
    3. 假设有国家Волгоград(Wolgograd),并且有只知道俄语字母的这个国家的市民。 在俄语字母表中В是第三个字母,所以当Волгоград接近列表的末尾(靠近委内瑞拉)时,这个人会在列表的开头(比利时和丹麦之间的某个地方)搜索。 所以在这种情况下,排序不仅没有帮助,而且还具有误导性。
    4. 如果有人知道拉丁字母并正在搜索他的国家,那么这并非易事。 当所有国家都以英文命名并且我正在寻找“波兰”时,我总是知道我是否应该在列表中上下。如果我看到“日本”,我知道要列入清单。当我看到'俄罗斯'时,我知道要上去。
      但如果我们对所有这些名称进行排序,那么可能会出现问题。如果我看到了ايران,那么我将无法决定是否上下列表。 所以在这个例子中,排序没有帮助。更糟糕的情况是我在名单上遇到Волгоград。我不知道俄语字母,我会认为我接近'B'字母,而实际上我接近列表的末尾。 然后我会选择错误的方向。
    5. <强>要点:

      对以不同语言编写的国家/地区名称进行排序很难定义和实施。实施后,它将无用或有害。

答案 1 :(得分:2)

也许您可以比较规范化的字符串。像这样:

private static final Comparator<DomainTO> DOMAIN_COUNTRY_COMPARATOR =
    new Comparator<DomainTO>() {

        private String normalize(final String input) {
            return Normalizer
                .normalize(input, Normalizer.Form.NFD)
                .replaceAll("[^\\p{ASCII}]", "");
        }

        @Override
        public int compare(final DomainTO t, final DomainTO t1) {
            return normalize(t.getCountry()).compareTo(
                normalize(t1.getCountry()));
        }
    };

请参阅有关规范化的相关问题:Converting Java String to ascii(此问题与几个类似的问题相关联)