Java处理中文排序

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

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);
        }
    
        System.out.println("张 UNICODE:" + Integer.toHexString('张'));
        System.out.println("李 UNICODE:" + Integer.toHexString('李'));
        System.out.println("王 UNICODE:" + Integer.toHexString('王'));
    }
}

 对应输出:

1、张三(Z)
2、李四(L)
3、王五(W)
张 UNICODE:5f20
李 UNICODE:674e
王 UNICODE:738b

我们希望是按照拼音升序排列,即为李四,王五,张三,但是结果却不是这样的.

这是按照什么进行排序的?Arrays工具类默认的排序是通过数组元素的compareTo()方法排序的,看其源代码实现:

public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
         //原字符串的字符数组
            char c1 = v1[k];
         //比较字符串的字符数组
            char c2 = v2[k];
            if (c1 != c2) {
           //比较两者的char值大小
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

上面代码先取得字符串的字符数组,然后一个个的比较大小,注意这里是字符比较(减号操作符),也就是UNICODE码值的比较,查UNICODE表,

"张"的码值是5F20,而"李"是674E,这样看"张"排在"李"前面也就很正确了.

这点在JDK文档中也有说明:对于非英文的String排序可能会出现不准确的情况,那该如何解决这个问题?Java推荐使用Collator类进行排序.

修改代码:

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

public class Client {
    @SuppressWarnings("unchecked")
    public static void main(String[] args) throws Exception {
        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)

汉字博大精深,最主要的一点是汉字 有象形文字,音行分离,并不是每个汉字都能按照拼音的顺序排列好.

看代码:

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

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

代码输出:

1、鑫(X)
2、犇(B)

 输出结果又乱了,只是因为汉字的文化博大精深.

更深层次的原因是Java使用的是UNICODE编码,而中文UNICODE字符集是源于GB18030的,GB18030又是从GB2312发展起来的,GB2312是一个包含了7000多个字符的字符集,它是按照拼音排序,并且是连续的.

之后的GBK,GB18030都是在其基础上扩充起来的.

如果是排序对象是经常使用的汉字,使用Collator类排序完全可以满足我们的需求.毕竟GB2312已经包含了大部分的汉字,如果需要严格排序,则要使用一些开源项目来自己实现了.

比如pinyon4j可以把汉字转换为拼音.然后我们自己来实现排序算法,不过此时也要考虑诸如算法,同音字,多音字等众多问题.

 

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

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值