You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何按后缀字母优先、前缀数字排序字符串列表?自定义Comparator失效

问题

我有如下字符串列表:

(2D, 1D, 1Y, 23M, 4M, 2Y, 12D)

需要实现先按后缀字母排序、再按前缀数字排序的效果,期望结果为:

(1D, 2D, 12D, 4M, 23M, 1Y, 2Y)

我尝试了以下代码但未能生效:

Collections.sort(myList, new MyComparator());

public class MyComparator implements Comparator {

    @Override
    public int compare(Object o1, Object o2) {

        String s1 = (String)o1;
        String s2 = (String)o2;
        String strPart1 = s1.split("")[1];
        int intPart1 = Integer.parseInt(s1.split("")[0]);

        String strPart2 = s2.split("")[1];
        int intPart2 = Integer.parseInt(s2.split("")[0]);

        int strCompareResult = strPart1.compareTo(strPart2);
        if(0 == strCompareResult )
        {
            return intPart1 - intPart2;
        }
        else
        {
            return strCompareResult;
        }
    }

}

请问该如何解决?


问题原因

你的代码核心问题在于字符串拆分逻辑错误:

  • s1.split("")会将字符串拆分为单个字符数组,比如"12D"会被拆成["1","2","D"],此时取索引0只能拿到第一个数字字符,索引1拿到第二个数字字符,根本无法正确提取完整的数字部分和后缀字母。
  • 当数字部分是多位数时(如12D、23M),这种拆分方式会导致解析数字时抛出NumberFormatException,因为你只取了单个字符转数字,而非完整的数字段。

正确实现

可以通过正则表达式或遍历字符串的方式,拆分出每个元素的数字部分和后缀字母,再执行排序逻辑。以下是两种可靠实现:

方案一:正则表达式(简洁高效)

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MyComparator implements Comparator<String> {
    // 匹配数字+后缀字母的正则,分组1为数字,分组2为后缀
    private static final Pattern PATTERN = Pattern.compile("(\\d+)([DMY])");

    @Override
    public int compare(String s1, String s2) {
        // 解析第一个字符串
        Matcher matcher1 = PATTERN.matcher(s1);
        matcher1.find();
        int num1 = Integer.parseInt(matcher1.group(1));
        String suffix1 = matcher1.group(2);

        // 解析第二个字符串
        Matcher matcher2 = PATTERN.matcher(s2);
        matcher2.find();
        int num2 = Integer.parseInt(matcher2.group(1));
        String suffix2 = matcher2.group(2);

        // 先比较后缀字母
        int suffixCompare = suffix1.compareTo(suffix2);
        if (suffixCompare != 0) {
            return suffixCompare;
        }
        // 后缀相同则比较数字大小
        return Integer.compare(num1, num2);
    }
}

// 使用方式不变
Collections.sort(myList, new MyComparator());

方案二:遍历字符串拆分(无正则依赖)

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class MyComparator implements Comparator<String> {
    @Override
    public int compare(String s1, String s2) {
        // 提取s1的数字和后缀
        int splitIndex1 = findSplitIndex(s1);
        int num1 = Integer.parseInt(s1.substring(0, splitIndex1));
        String suffix1 = s1.substring(splitIndex1);

        // 提取s2的数字和后缀
        int splitIndex2 = findSplitIndex(s2);
        int num2 = Integer.parseInt(s2.substring(0, splitIndex2));
        String suffix2 = s2.substring(splitIndex2);

        int suffixCompare = suffix1.compareTo(suffix2);
        if (suffixCompare != 0) {
            return suffixCompare;
        }
        return Integer.compare(num1, num2);
    }

    // 找到第一个非数字字符的索引,即后缀的起始位置
    private int findSplitIndex(String s) {
        int index = 0;
        while (index < s.length() && Character.isDigit(s.charAt(index))) {
            index++;
        }
        return index;
    }
}

补充说明
  • 建议使用泛型Comparator<String>代替原始Comparator,避免强制类型转换,提升代码安全性。
  • 使用Integer.compare(num1, num2)比直接num1 - num2更稳妥,可避免整数溢出问题。

内容的提问来源于stack exchange,提问作者user3809938

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 13:52:49