Java如何实现拼音排序?

在我们国家,按拼音进行排序是很常见的需求,比如姓名,那如何按拼音进行排序呢?

假如我们有以下List:

List<String> list = new ArrayList<>();
list.add("周瑜");
list.add("大都督");
list.add("周文王");
list.add("周武王");
list.add("周公");

如果我们采用最简单的排序方式:

list.sort(String::compareTo);

结果为:

[周公, 周文王, 周武王, 周瑜, 大都督]

很明显,结果不是拼音顺序,“大都督”应该要在最前面,那这种情况是按什么逻辑排的序呢?

上面的排序代码相当于:

list.sort(new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return s1.compareTo(s2);
    }
});

本质上是比较两个String的大小,小的排在前面,大的排在后面,那两个String默认是怎么比较大小的呢?

通过查看compareTo的源码,发现底层调用的是:

StringUTF16.compareTo(s1, s2)

因此,本质上比较的是两个String的UTF16编码的大小关系,比如:

  • “周瑜”的UTF16编码为:54 68 74 5C
  • “大都督”的UTF16编码为:59 27 90 FD 77 63

很明显,直接比较第一个字节就能发现“周瑜”小于“大都督”,因为54小于59,所以在排序结果中,“周瑜”排在了“大都督”的前面。

原谅我,以上都是铺垫,接下来才是正文,那如何按拼音进行排序呢?

排序的本质其实都一样,都是把字符转成特定的编码,然后比较编码的大小关系,那么有没有一种编码是按拼音来编码的呢?

有,那就是GBK。

比如:

  • “啊”的GKB编码为:B0 A1
  • “阿”的GKB编码为:B0 A2

或者,大家可以直接去看GBK的编码表:GBK编码表

我截其中一部分
image.png

可以发现,GBK是妥妥的按拼音顺序来的。

因此,我们只需要将字符串按GBK进行编码然后比较大小,就可以实现按拼音排序了,比如:

list.sort(new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        try {
            byte[] s1Bytes = s1.getBytes("GBK");
            byte[] s2Bytes = s2.getBytes("GBK");

            int s1Size = s1Bytes.length;
            int s2Size = s2Bytes.length;

            int size = Math.min(s1Size, s2Size);

            for (int i = 0; i < size; i++) {
                byte b1 = s1Bytes[i];
                byte b2 = s2Bytes[i];

                if (b1 != b2) {
                    return b1 - b2;
                }
            }

            return s1Size - s2Size;
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }

    }
});

这样,结果就变为了:

[大都督, 周公, 周文王, 周武王, 周瑜]

符合预期。

当然,上面的代码写的比较粗糙,Java中有现成的实现,比如:

list.sort(new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return Collator.getInstance(Locale.CHINESE).compare(s1, s2);

    }
});

结果也是:

[大都督, 周公, 周文王, 周武王, 周瑜]

或者你可以直接用Hutool提供的封装好的方法:

CollUtil.sortByPinyin(list);

本质都是一样的,都是按GBK来进行编码和排序的。

这就是拼音排序,感谢大家的点赞、关注、分享,谢谢。

我是大都督周瑜,欢迎关注我的公众号:IT周瑜,我会持续分享深度技术文章、常见经典面试题、学习路线、职业规范、实战经验。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值