复杂字符串排序(含数字、字母、汉字)升序

近期,项目中遇到一个恶心排序的问题,字符串中存在数字、字母、汉字,要求先按照数字升序、字母升序、最后再汉字升序排序。

通过各种找资料,最后重写compare()方法解决了,特意记录下

package com.baosight.nnplat.common.utils;


import java.util.Comparator;

/**
* 创建字符串排序工具类
* 字符串排序
* 含数字、字母、汉字
*/
public class NaturalOrderComparator implements Comparator {
    int compareRight(String a, String b) {
        int bias = 0, ia = 0, ib = 0;


        // The longest run of digits wins. That aside, the greatest
        // value wins, but we can't know that it will until we've scanned
        // both numbers to know that they have the same magnitude, so we
        // remember it in BIAS.
        for (; ; ia++, ib++) {
            char ca = charAt(a, ia);
            char cb = charAt(b, ib);


            if (!isDigit(ca) && !isDigit(cb)) {
                return bias;
            }
            if (!isDigit(ca)) {
                return -1;
            }
            if (!isDigit(cb)) {
                return +1;
            }
            if (ca == 0 && cb == 0) {
                return bias;
            }


            if (bias == 0) {
                if (ca < cb) {
                    bias = -1;
                } else if (ca > cb) {
                    bias = +1;
                }
            }
        }
    }


    @Override
    public int compare(Object o1, Object o2) {
        String a = o1.toString();
        String b = o2.toString();


        int ia = 0, ib = 0;
        int nza = 0, nzb = 0;
        char ca, cb;


        while (true) {
            // Only count the number of zeroes leading the last number compared
            nza = nzb = 0;


            ca = charAt(a, ia);
            cb = charAt(b, ib);


            // skip over leading spaces or zeros
            while (Character.isSpaceChar(ca) || ca == '0') {
                if (ca == '0') {
                    nza++;
                } else {
                    // Only count consecutive zeroes
                    nza = 0;
                }


                ca = charAt(a, ++ia);
            }


            while (Character.isSpaceChar(cb) || cb == '0') {
                if (cb == '0') {
                    nzb++;
                } else {
                    // Only count consecutive zeroes
                    nzb = 0;
                }


                cb = charAt(b, ++ib);
            }


            // Process run of digits
            if (Character.isDigit(ca) && Character.isDigit(cb)) {
                int bias = compareRight(a.substring(ia), b.substring(ib));
                if (bias != 0) {
                    return bias;
                }
            }


            if (ca == 0 && cb == 0) {
                // The strings compare the same. Perhaps the caller
                // will want to call strcmp to break the tie.
                return compareEqual(a, b, nza, nzb);
            }
            if (ca < cb) {
                return -1;
            }
            if (ca > cb) {
                return +1;
            }


            ++ia;
            ++ib;
        }
    }


    static boolean isDigit(char c) {
        return Character.isDigit(c) || c == '.' || c == ',';
    }


    static char charAt(String s, int i) {
        return i >= s.length() ? 0 : s.charAt(i);
    }


    static int compareEqual(String a, String b, int nza, int nzb) {
        if (nza - nzb != 0) {
            return nza - nzb;
        }


        if (a.length() == b.length()) {
            return a.compareTo(b);
        }


        return a.length() - b.length();
    }


}
    @Test
      public void test11(){
              //String[] strings = new String[]{"5栋", "7栋", "4栋", "15栋", "24栋", "涉外国际6栋","国际7栋",  "B666栋", "B17栋",  "B1栋","A45栋","A22栋"};
              String[] strings = new String[]{"2C1", "2C3", "2C2", "2C4"};
              List scrambled = Arrays.asList(strings);
              Collections.shuffle(scrambled);
              Collections.sort(scrambled, new NaturalOrderComparator());
              
              System.out.println("排序后: " + scrambled);
              String str = (String)  scrambled.stream().collect(Collectors.joining(","));
              System.out.println("排序后: " + str);
      }

输出:

结果:
排序后: [4栋, 5栋, 7栋, 15栋, 24栋, A22栋, A45栋, B1栋, B17栋, B666栋, 国际7栋,  涉外国际6栋]
排序后: 4栋,5栋,7栋,15栋,24栋,A22栋,A45栋,B1栋,B17栋,B666栋,国际7栋,涉外国际6栋

排序后: [2C1, 2C2, 2C3, 2C4]
排序后: 2C1,2C2,2C3,2C4

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值