1,当我使用如下代码对其中的list进行排序时: 优先级以特殊字符、数字、英文、汉字(且汉字部分以汉字首字母)顺序排序

@Test
    public void sortList(){
        List<String>list=Lists.newArrayList();
        list.add("好好");
        list.add("最好");
        list.add("啊");
        list.add("##");
        list.add("嗯嗯");
        list.add("--");
        list.add("*");
        list.add("--");
        list.add("可以");
        list.add("56");
        list.add("");
        list.add(" ");
        list.add("bbbb");
        list.add("acc");
        list.add("52");
        list.add("aaaa");

        Comparator<Object> CHINA_COMPARE = Collator.getInstance(java.util.Locale.CHINA);
        list.sort((o1, o2) -> ((Collator) CHINA_COMPARE).compare(o1, o2));

        System.out.println(list.toString());
    }

输出结果为:

[,  , --, --, *, ##, 52, 56, aaaa, acc, bbbb, 啊, 好好, 可以, 最好, 嗯嗯]

总体上看,好像是达到了目的,细分析,发现了其中“嗯嗯”竟然排在了“最好“的后台,这就不符合按照汉字首字母进行排序的规则了,所以”嗯“的排序出现了异常。且不知道还有多少未知的汉字也会出现这样的排序异常,所以可以初步断定,

Comparator<Object> CHINA_COMPARE = Collator.getInstance(java.util.Locale.CHINA);

比较器,并不能很好的让汉字按照首字母拼音进行排序,但是对特殊字符、数字、英文进行排序初步断定是没问题的。

2,解决方案:

经过1中问题的分析,可以考虑将列表分成两个部分:非汉字部分和汉字部分,然后分别进行排序,最后将两部分合并。

非汉字部分排序可以使用上面的方法。下面重点就是解决汉字部分的排序,可以先将汉字转为拼音,然后再进行比较排序。

但是注意:不能和非汉字部分和汉字部分一起都转成拼音排序:1是先不说殊死字符无法转换成拼音的问题;2其次也因为将汉字转成拼音后,和原来本身就是英文的部分混合一起进行比较,就无法保证英文部分能够排在汉字的前面了。

3,代码示例:

运行下面代码,最后输出结果为:

[,  , --, --, *, ##, 52, 56, aaaa, acc, bbbb, 啊, 好好, 可以, 嗯嗯, 最好]
import com.google.common.collect.Lists;
import com.netease.ai.ar.dongjian.util.Pinyin4jUtil;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.text.Collator;
import java.util.Comparator;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: Weichang Zhong
 * @Date: 2018/10/18
 * @Time: 16:22
 * @Description:
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class testBug {

    @Test
    public void sortList(){
        List<String> list = Lists.newArrayList();
        list.add("好好");
        list.add("最好");
        list.add("啊");
        list.add("##");
        list.add("嗯嗯");
        list.add("--");
        list.add("*");
        list.add("--");
        list.add("可以");
        list.add("56");
        list.add("");
        list.add(" ");
        list.add("bbbb");
        list.add("acc");
        list.add("52");
        list.add("aaaa");

        // 将list集合分成只包含以汉字开头元素的集合和不包含以汉字开头元素的集合
        List<String> chineseCharacters = Lists.newArrayList();
        List<String> notChineseCharacters = Lists.newArrayList();
        for(String str: list) {
            if(StringUtils.isNotEmpty(str) && String.valueOf(str.charAt(0)).matches("[\u4e00-\u9fa5]")) {
                // 如果开头为汉字,则加入汉字列表中
                chineseCharacters.add(str);
            }else {
                notChineseCharacters.add(str);
            }
        }

        Comparator<Object> com = Collator.getInstance(java.util.Locale.CHINA);
        // 先对非汉字开头内容进行排序
        notChineseCharacters.sort((o1, o2) -> ((Collator) com).compare(o1, o2));
        // 以汉字开头的,先将汉字转成拼音,然后进行排序
        Pinyin4jUtil pinyin4jUtil = new Pinyin4jUtil();
        chineseCharacters.sort((o1, o2) -> ((Collator) com).compare(pinyin4jUtil.getStringPinYin(o1), pinyin4jUtil.getStringPinYin(o2)));
        notChineseCharacters.addAll(chineseCharacters);
        System.out.println(notChineseCharacters.toString());
    }
}

其中Pinyin4jUtil.java

import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: Weichang Zhong
 * @Date: 2018/12/7
 * @Time: 9:25
 * @Description:
 */
public class Pinyin4jUtil {


    /** pinyin4j格式类 **/
    private HanyuPinyinOutputFormat format = null;
    /** 拼音字符串数组 **/
    private String[]pinyin;

    /** 通过构造方法进行初始化 **/
    public Pinyin4jUtil(){

        format = new HanyuPinyinOutputFormat();
        /*
         * 设置需要转换的拼音格式
         * 以天为例
         * HanyuPinyinToneType.WITHOUT_TONE 转换为tian
         * HanyuPinyinToneType.WITH_TONE_MARK 转换为tian1
         * HanyuPinyinVCharType.WITH_U_UNICODE 转换为tiān
         *
         */
        format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        pinyin = null;
    }

    /**
     * 对单个字进行转换
     * @param pinYinStr 需转换的汉字字符串
     * @return 拼音字符串数组
     */
    public String getCharPinYin(char pinYinStr){

        try
        {
            //执行转换
            pinyin = PinyinHelper.toHanyuPinyinStringArray(pinYinStr, format);

        } catch (BadHanyuPinyinOutputFormatCombination e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        //pinyin4j规则,当转换的符串不是汉字,就返回null
        if(pinyin == null){
            return null;
        }

        //多音字会返回一个多音字拼音的数组,pinyiin4j并不能有效判断该字的读音
        return pinyin[0];
    }

    /**
     * 对单个字进行转换
     * @param pinYinStr
     * @return
     */
    public String getStringPinYin(String pinYinStr) {
        StringBuffer sb = new StringBuffer();
        String tempStr = null;
        //循环字符串
        for (int i = 0; i < pinYinStr.length(); i++) {

            tempStr = this.getCharPinYin(pinYinStr.charAt(i));
            if (tempStr == null) {
                //非汉字直接拼接
                sb.append(pinYinStr.charAt(i));
            } else {
                sb.append(tempStr);
            }
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        Pinyin4jUtil pinyin4jUtil = new Pinyin4jUtil();
        String str = "你在做什么?what are you nong sa lie?";
        System.out.println(pinyin4jUtil.getStringPinYin(str));

        System.out.println(String.valueOf(str.charAt(0)).matches("[\u4e00-\u9fa5]"));

    }

}

pom 引入的maven jar包:

<dependency>
            <groupId>net.sourceforge.pinyin4j</groupId>
            <artifactId>pinyin4j</artifactId>
            <version>2.5.0</version>
        </dependency>