最近在做项目的时候遇到了一个针对集合需要按字母从a到z进行排序的问题,可是集合中的元素有的全是英文,有的全是中文,而有的还是中英文结合,上网搜了一下第一反应用的是Collator,对于什么是Collator大家可以上网搜索了解一下,这里就不做详细介绍了。
但是Collator有一个问题,就是Java并不能精确的对所有的汉字进行排序,比如对“犇”和“鑫”进行排序,只是因为我们的汉字文化太博大精深了,要做好这个排序确实有点难为Java了。更深层次的原因是Java使用的是 UNICODE 编码,而中文 UNICODE 字符集是来源于 GB18030 的,GB18030 又是从GB2312 发展起来的, GB2312 是一个包含 7000 多个字符的字符集,它是按照拼音排序,并且是连续的,之后的 GBK、GB2312 都是在起基础上扩充而来的,所以要让它们完整排序也就难上加难了。但如果排序对象是经常使用的汉字,使用Collator类排序完全可以满足我们的要求。 如果需要严格排序,可以使用一些开源项目来自己实现,比如 pinyin4j 可以把汉字转换为拼音,然后我们自己来实现排序算法,不过此时你也会发现要考虑诸如算法、同音字、多音字等众多问题。 pinyin4j下载地址:http://pinyin4j.sourceforge.net/, 嗯哼,这句话也不是我说的,是这篇博客:https://blog.csdn.net/u010039979/article/details/53583445
然后,我就尝试使用pinyin4j编写了一个比较器,下面具体说一下:
1.首先添加pom依赖
<!-- https://mvnrepository.com/artifact/com.belerweb/pinyin4j -->
<dependency>
<groupId>com.belerweb</groupId>
<artifactId>pinyin4j</artifactId>
<version>2.5.0</version>
</dependency>
2.编写比较器:代码如下
package com.xh.list;
import net.sourceforge.pinyin4j.PinyinHelper;
import java.util.Comparator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author:
* @Description
* @Date: 2018/9/10 13:59
*/
public class HanYuPinYinComparator implements Comparator<String> {
//调用pinyin4j工具类
private String concatPinyinStringArray(String[] pinyinArray) {
StringBuffer pinyinSbf = new StringBuffer();
if ((pinyinArray != null) && (pinyinArray.length > 0)) {
for (int i = 0; i < pinyinArray.length; i++) {
pinyinSbf.append(pinyinArray[i]);
}
}
return pinyinSbf.toString();
}
@Override
public int compare(String o1, String o2) {
if (o1 == null || o2 == null || o1.equals("") || o2.equals("") || o1.equals(o2)) return 0;
//以汉字少的为基准
for(int i = 0; i < Math.min(o1.length(), o2.length()); i++){
char c1 = o1.charAt(i);
char c2 = o2.charAt(i);
if(isChinese(c1+"") && isChinese(c2+"")){//比较两个字符都是汉字的情况
int result = concatPinyinStringArray(
PinyinHelper.toHanyuPinyinStringArray(c1)).compareToIgnoreCase(
concatPinyinStringArray(PinyinHelper
.toHanyuPinyinStringArray(c2)));
//如果比较结果相同,就比较下一个汉字
if(result == 0){
continue;
}
return result;
}else if(isChinese(c1+"") && !isChinese(c2+"")){//比较前者是汉字后者为非汉字的情况
int result = (concatPinyinStringArray(PinyinHelper
.toHanyuPinyinStringArray(c1))).compareToIgnoreCase(c2+"");
if(result == 0){
continue;
}
return result;
}else if(!isChinese(c1+"") && isChinese(c2+"")){//比较后者是汉字前者为非汉字的情况
int result =(c1+"").compareToIgnoreCase(concatPinyinStringArray(PinyinHelper
.toHanyuPinyinStringArray(c2)));
if(result == 0){
continue;
}
return result;
}else {//比较
int result = (c1+"").compareToIgnoreCase(c2+"");
if(result == 0){
continue;
}
return result;
}
}
//如果程序执行到这行两个字符串相比较的部分都相同,那么字符串长度长的定义为大
return (o1.length() - o2.length())<0?-1:(o1.length() - o2.length())==0?0:1;
}
/**
* 判断是否为汉字
* @param str 字
* @return
*/
public boolean isChinese(String str) {
Pattern p_str = Pattern.compile("[\\u4e00-\\u9fa5]+");
Matcher m = p_str.matcher(str);
if(m.find()&&m.group(0).equals(str)){
return true;
}
return false;
}
}
3.编写一个测试demo测试一下:
package com.xh.list;
import java.text.Collator;
import java.util.*;
public class TestDemo {
public static void main(String[] args){
List<String> list = new ArrayList<>();
list.add("呲牙");
list.add("震惊");
list.add("尴尬");
list.add("haha菠菜");
list.add("喵喵");
list.add("咒骂");
list.add("aaaa这是");
list.add("蝙蝠侠");
list.add("aa");
Collections.sort(list, new HanYuPinYinComparator());
for(String str:list){
System.out.println(str);
}
}
}
4.观察一下输出结果吧:
aa
aaaa这是
蝙蝠侠
呲牙
尴尬
haha菠菜
喵喵
震惊
咒骂
Process finished with exit code 0
完美解决!!!希望能帮到该需求的小伙伴