Java_String_对字符串排序持一种宽容的心态

在Java中一涉及中文处理就会冒出很多问题来,其中排序也是一个让人头疼的问题,我们来看下面的代码:

package deep;

import java.util.Arrays;

public class Client {

    public static void main(String[] args) {
        String[] strs = { "张三(Z)", "李四(L)", "王五(W)" };
        // 排序,默认是升序
        Arrays.sort(strs);
        int i = 0;
        for (String str : strs) {
            System.out.println((++i) + "、" + str);
        }
    }

}

运行结果:
1、张三(Z)
2、李四(L)
3、王五(W)

上面的代码定义了一个数组,然后进行升序排序,我们期望的结果是按照拼音升序排列,即为李四、王五、张三,但是结果却不是这样的。
这是按照什么排序的呀,非常混乱!我们知道Arrays工具类的默认排序是通过数组元素的compareTo方法来进行比较的,那我们来看String类的compareTo的主要实现:

        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }

上面的代码先取得字符串的字符数组,然后一个一个地比较大小,注意这里是字符比较(减号操作符),也就是UNICODE码值的比较,查一下UNICODE代码表,“张”的码值是5F20,而“李”是674E,这样一看,“张”排在“李”的前面也就很正确了——但这明显和我们的意图冲突了。这一点在JDK文档中也有说明:对于非英文的String排序可能会出现不准确的情况。那该如何解决这个问题呢?Java推荐使用Collator类进行排序,那好,我们把代码修改一下:

package deep;

import java.text.Collator;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Locale;

public class Client {

    public static void main(String[] args) {
        String[] strs = { "张三(Z)", "李四(L)", "王五(W)" };
        // 定义一个中文排序器
        Comparator c = Collator.getInstance(Locale.CHINA);
        // 升序排列
        Arrays.sort(strs, c);
        int i = 0;
        for (String str : strs) {
            System.out.println((++i) + "、" + str);
        }
    }

}

运行结果:
1、李四(L)
2、王五(W)
3、张三(Z)

这确实是我们期望的结果,应该举杯庆贺了吧!但是且慢,中国的汉字博大精深,Java是否都能精确的排序呢?最主要的一点是汉字中有象形文字,音形分离,是不是每个汉字都能按照拼音的顺序排列好呢?我们写一个复杂的汉字来看看:

package deep;

import java.text.Collator;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Locale;

public class Client {

    public static void main(String[] args) {
        String[] strs = { "犇(B)", "鑫(X)" };
        Comparator c = Collator.getInstance(Locale.CHINA);
        Arrays.sort(strs, c);
        int i = 0;
        for (String str : strs) {
            System.out.println((++i) + "、" + str);
        }
    }

}

运行结果:
1、鑫(X)
2、犇(B)

三个牛“犇”念ben,三个金“鑫”念xin,这两个字经常出现在饭店和商店的名称上,但输出的结果是乱的!不要责怪Java,它已经尽量为我们考虑了,只是因为我们的汉字文化太博大精深了,要做好这个排序确实有点难为它。更深层次的原因是Java使用的是UNICODE编码,而中文UNICODE字符集是来源于GB18030的,GB18030又是从GB2312发展起来,GB2312是一个包含了7000多个字符的字符集,它是按照拼音排序,并且是连续的,之后的GBK、GB18030都是在其基础上扩充出来的,所以要让它们完整排序也就难上加难了。
如果需排序对象是经常使用的汉字,使用Collator类排序完全可以满足我们的要求,毕竟GB2312已经包含了大部分的文字,如果需要严格排序,则要使用一些开源项目来自己实现了,比如pinyin4j可以把汉字转换为拼音,然后我们自己来实现排序算法,不过此时你也会发现要考虑诸如算法、同音字、多音字等众多问题。

注:如果排序不是一个关键算法,使用Collator类即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值