47

Java 中文字符按Unicode排序

 5 years ago
source link: http://www.zhyea.com/2018/10/30/java-string-in-chinese-sort-with-unicode.html?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

遇到了一个对包含中文的字符串进行排序的问题。要求按unicode编码对字符串进行排序。

测试字符串数组如下:

        String[] arr = {
                "1-测试",
                "1-编辑",
                "1-营销",
                "1结束",
                "2-测试",
                "1-qt"
        };

按unicode排序的期望结果应该是这样的:

1-编辑, 1-测试, 1-营销, 1-qt, 1结束, 2-测试

先按java.lang.String类提供的默认比较方案进行实现,大致如下:

import java.util.Arrays;
import java.util.Comparator;
 
public class MyJob {
 
 
    public static void main(String[] args) {
 
        String[] arr = {
                "1-测试",
                "1-编辑",
                "1-营销",
                "1结束",
                "2-测试",
                "1-qt"
        };
 
        Comparator<String> c = String::compareTo;
 
        Arrays.sort(arr, c);
 
        System.out.println(Arrays.toString(arr));
    }
}

结果如下:

[1-qt, 1-测试, 1-编辑, 1-营销, 1结束, 2-测试]

可以看到中文字符不能按照拼音进行排序。这时最直接的思路就是将中文字符转为拼音后再进行排序。但是要注意下,在这里面有个字符串不包含中文字符,这就容易导致顺序混乱。

如下面这几个字符串按拼音进行排序顺序如下:

1-编辑,1-测试,1-qt,1-营销

可以看到字符串“1-qt”的位置出错了。 但是按拼音来说它的位置又是对的。这不能不说是一个让人有些头疼的地方。

不过不用担心,java提供了java.text.Collator类来支持规范化的字符串比较。

使用Collator来改造之前的代码:

import java.text.Collator;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Locale;
 
public class MyJob {
 
 
    public static void main(String[] args) {
 
        String[] arr = {
                "1-测试",
                "1-编辑",
                "1-营销",
                "1结束",
                "2-测试",
                "1-qt"
        };
 
        Comparator<String> c = (o1, o2) -> Collator.getInstance(Locale.CHINESE).compare(o1, o2);
 
        Arrays.sort(arr, c);
 
        System.out.println(Arrays.toString(arr));
    }
}

改造后的程序执行排序的结果如下:

[1-qt, 1-编辑, 1-测试, 1结束, 1-营销, 2-测试]

结果看着好像还OK。但是停停、注意下、字符串“1结束”的位置好像比较奇妙,理想情况下它应该在“1-营销”的后面。

这里出问题的原因我没有弄清楚。猜测着应该是java在Chinese语法中将中划线处理为空字符了。不过最根本的问题还是java对Unicode Collation Algorithm(UCA,Unicode整理算法)的支持并不好。

此时可以考虑使用IBM ICU提供的Collator来替换jdk默认的Collator。代码如下:

import com.ibm.icu.text.Collator;
 
import java.util.Arrays;
import java.util.Comparator;
import java.util.Locale;
 
public class MyJob {
 
 
    public static void main(String[] args) {
 
        String[] arr = {
                "1-测试",
                "1-编辑",
                "1-营销",
                "1结束",
                "2-测试",
                "1-qt"
        };
 
        Comparator<String> c = (o1, o2) -> Collator.getInstance(Locale.CHINESE).compare(o1, o2);
 
        Arrays.sort(arr, c);
 
        System.out.println(Arrays.toString(arr));
    }
}

相关的依赖为:

        <dependency>
            <groupId>com.ibm.icu</groupId>
            <artifactId>icu4j-localespi</artifactId>
            <version>60.2</version>
        </dependency>

执行结果为:

[1-编辑, 1-测试, 1-营销, 1-qt, 1结束, 2-测试]

可以看到是和预期一致的。

参考文档

##########


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK