在Java中一涉及到中文处理就会冒出很多的问题来,其中的排序也是一个让人头疼的问题,看代码:
1 import java.util.Arrays; 2 3 public class Client { 4 public static void main(String[] args){ 5 String[] strs = {"张三(Z)","李四(L)","王五(W)"}; 6 //排序,默认是升序 7 Arrays.sort(strs); 8 int i=0; 9 for(String str:strs){ 10 System.out.println((++i) + "、"+ str); 11 } 12 13 System.out.println("张 UNICODE:" + Integer.toHexString('张')); 14 System.out.println("李 UNICODE:" + Integer.toHexString('李')); 15 System.out.println("王 UNICODE:" + Integer.toHexString('王')); 16 } 17 }
对应输出:
1、张三(Z) 2、李四(L) 3、王五(W) 张 UNICODE:5f20 李 UNICODE:674e 王 UNICODE:738b
我们希望是按照拼音升序排列,即为李四,王五,张三,但是结果却不是这样的.
这是按照什么进行排序的?Arrays工具类默认的排序是通过数组元素的compareTo()方法排序的,看其源代码实现:
1 public int compareTo(String anotherString) { 2 int len1 = value.length; 3 int len2 = anotherString.value.length; 4 int lim = Math.min(len1, len2); 5 char v1[] = value; 6 char v2[] = anotherString.value; 7 8 int k = 0; 9 while (k < lim) {
//原字符串的字符数组 10 char c1 = v1[k];
//比较字符串的字符数组 11 char c2 = v2[k]; 12 if (c1 != c2) {
//比较两者的char值大小 13 return c1 - c2; 14 } 15 k++; 16 } 17 return len1 - len2; 18 }
上面代码先取得字符串的字符数组,然后一个个的比较大小,注意这里是字符比较(减号操作符),也就是UNICODE码值的比较,查UNICODE表,
"张"的码值是5F20,而"李"是674E,这样看"张"排在"李"前面也就很正确了.
这点在JDK文档中也有说明:对于非英文的String排序可能会出现不准确的情况,那该如何解决这个问题?Java推荐使用Collator类进行排序.
修改代码:
1 import java.text.Collator; 2 import java.util.Arrays; 3 import java.util.Comparator; 4 import java.util.Locale; 5 6 public class Client { 7 @SuppressWarnings("unchecked") 8 public static void main(String[] args) throws Exception { 9 String[] strs = {"张三(Z)","李四(L)","王五(W)"}; 10 //定义一个中文排序器 11 Comparator c = Collator.getInstance(Locale.CHINA); 12 //升序排列 13 Arrays.sort(strs,c); 14 int i=0; 15 for(String str:strs){ 16 System.out.println((++i) + "、"+ str); 17 } 18 } 19 }
输出结果:
1、李四(L) 2、王五(W) 3、张三(Z)
汉字博大精深,最主要的一点是汉字 有象形文字,音行分离,并不是每个汉字都能按照拼音的顺序排列好.
看代码:
1 import java.text.Collator; 2 import java.util.Arrays; 3 import java.util.Locale; 4 5 public class Client { 6 public static void main(String[] args) throws Exception { 7 String[] strs = {"犇(B)","鑫(X)"}; 8 Arrays.sort(strs,Collator.getInstance(Locale.CHINA)); 9 int i=0; 10 for(String str:strs){ 11 System.out.println((++i) + "、"+ str); 12 } 13 } 14 }
代码输出:
1、鑫(X)
2、犇(B)
输出结果又乱了,只是因为汉字的文化博大精深.
更深层次的原因是Java使用的是UNICODE编码,而中文UNICODE字符集是源于GB18030的,GB18030又是从GB2312发展起来的,GB2312是一个包含了7000多个字符的字符集,它是按照拼音排序,并且是连续的.
之后的GBK,GB18030都是在其基础上扩充起来的.
如果是排序对象是经常使用的汉字,使用Collator类排序完全可以满足我们的需求.毕竟GB2312已经包含了大部分的汉字,如果需要严格排序,则要使用一些开源项目来自己实现了.
比如pinyon4j可以把汉字转换为拼音.然后我们自己来实现排序算法,不过此时也要考虑诸如算法,同音字,多音字等众多问题.
如果排序不是一个关键算法,使用Collator类即可.