Java字符串数字比较器

Java字符串数字比较器,java,natural-sort,Java,Natural Sort,我有一个方法返回需要排序的字符串列表。然而,我遇到了旧的字符串编号排序问题,我想知道是否有人可以帮助比较器实现,或者为我指明一个方向 列表将返回以下内容: State Lower Legislative District 1 State Lower Legislative District 11 State Lower Legislative District 12 ... State Lower Legislative District 2 ... State Lower Legislativ

我有一个方法返回需要排序的字符串列表。然而,我遇到了旧的字符串编号排序问题,我想知道是否有人可以帮助比较器实现,或者为我指明一个方向

列表将返回以下内容:

State Lower Legislative District 1
State Lower Legislative District 11
State Lower Legislative District 12
...
State Lower Legislative District 2
...
State Lower Legislative District 100
...
State Upper Legislative District 1
State Upper Legislative District 11
...
首先我需要做一个基本的字符串排序,然后我需要按数字排序。要排序的数字应该始终是尾随的,可以是2或3位数字

(编辑)我最初的想法是在空格上拆分字符串,在数字部分运行StringUtils.isNumeric,然后排序。然而,这对我来说似乎有点困难


有人能帮忙吗?

一种方法是使用一个简单的正则表达式解析出比较器中感兴趣的字段,然后手动进行比较。以下是一个未经测试的示例:

private static final Pattern pattern = Pattern.compile("^State (Lower|Upper) Legislative District (\\d+)$");

public int compare(String a, String b) {
    Matcher matcher1 = pattern.matcher(a);
    Matcher matcher2 = pattern.matcher(b);
    if( matcher1.matches() && matcher2.matches() ) {
        //compare upper/lower
        int upperLowerComparison = matcher1.group(1).compareTo(matcher2.group(1));
        if ( upperLowerComparison != 0 ) {
            return upperLowerComparison;
        }

        //number comparison
        return Integer.valueOf(matcher1.group(2)).compareTo(Integer.valueOf(matcher2.group(2));
    }

    //...what to do if they don't match?
}

你有两个选择。第一个是创建一个包含两个字段的类-名称和编号。当然,首先要解析名称和数字。然后在比较器中,首先比较名称,然后比较数字。第二个是在
compare
方法中的适当位置进行解析。选择哪一个更适合你。

有关于编码的选项。这被称为,在这里,您可以有效地将一组数字视为单个“字符”。有关该想法的一些Java实现,请参见

人类排序:自然排序顺序 几乎所有编程语言中的默认排序函数都不适合人类使用。我这是什么意思?那么,考虑Windows资源管理器中排序文件名的差异,并通过<代码>数组.Sort()/<代码>代码:< /P>排序那些非常相同的文件名。


我通常通过在数字前面加零来实现,并将整个实体作为字符串处理。然后分类

见此:

public abstract class MyNumberComparator {

    protected int doCompare(final String number1, final String number2) {
       String strNumber1 = fillUpLeftWithZeros(number1, 30);
       String strNumber2 = fillUpLeftWithZeros(number2, 30);    

       return strNumber1.toUpperCase().compareTo(strNumber2.toUpperCase());    
   }

}

一个简单的实现如下所示(这适用于任何以数字结尾的字符串):

公共类SplitComparator实现Comparator{
静态类对实现了可比较的{
私有字符串名称;
私有整数;
公共对(字符串值){
value=value.trim();
this.name=value.substring(0,value.lastIndexOf(“”);
this.number=Integer.valueOf(value.substring(value.lastIndexOf(“”+1,value.length());
}
@凌驾
公共整数比较(右对){
int result=this.name.compareTo(right.name);
如果(结果==0){
结果=此.number.compareTo(right.number);
}
返回结果;
} 
}
@凌驾
公共整数比较(字符串左,字符串右){
返回新的一对(左)。比较(新的一对(右));
}
公共静态void main(字符串…参数){
字符串[]值={“州下立法区1”,
“州下立法区11”,
“州上立法区1”,
“州上立法区11”};
SplitComparator comparator=新的SplitComparator();
System.out.println(comparator.compare(值[1],值[0]);
System.out.println(comparator.compare(值[0],值[1]);
System.out.println(comparator.compare(值[0],值[3]);
}
}

我在String.compare上编写了一个变体,用于比较在两个字符串中找到的数字的长度。当遇到两个长度相同的数字时,字母数字比较将恢复正常。它还跳过前导零

public static int compareNatural(String a, String b) {
    int la = a.length();
    int lb = b.length();
    int ka = 0;
    int kb = 0;
    while (true) {
        if (ka == la)
            return kb == lb ? 0 : -1;
        if (kb == lb)
            return 1;
        if (a.charAt(ka) >= '0' && a.charAt(ka) <= '9' && b.charAt(kb) >= '0' && b.charAt(kb) <= '9') {
            int na = 0;
            int nb = 0;
            while (ka < la && a.charAt(ka) == '0')
                ka++;
            while (ka + na < la && a.charAt(ka + na) >= '0' && a.charAt(ka + na) <= '9')
                na++;
            while (kb < lb && b.charAt(kb) == '0')
                kb++;
            while (kb + nb < lb && b.charAt(kb + nb) >= '0' && b.charAt(kb + nb) <= '9')
                nb++;
            if (na > nb)
                return 1;
            if (nb > na)
                return -1;
            if (ka == la)
                return kb == lb ? 0 : -1;
            if (kb == lb)
                return 1;

        }
        if (a.charAt(ka) != b.charAt(kb))
            return a.charAt(ka) - b.charAt(kb);
        ka++;
        kb++;
    }
}
public static int compareNatural(字符串a、字符串b){
int la=a.长度();
int lb=b.长度();
int ka=0;
int kb=0;
while(true){
如果(ka==la)
返回kb==lb?0:-1;
如果(kb==lb)
返回1;
如果(a.charAt(ka)>='0'和a.charAt(ka)='0'和b.charAt(kb)='0'和a.charAt(ka+na)='0'和b.charAt(kb+nb)nb)
返回1;
如果(nb>na)
返回-1;
如果(ka==la)
返回kb==lb?0:-1;
如果(kb==lb)
返回1;
}
如果(a.charAt(ka)!=b.charAt(kb))
返回a.charAt(ka)-b.charAt(kb);
ka++;
kb++;
}
}

看看这个实现:

public static int naturalCompare(String a, String b, boolean ignoreCase) {
    if (ignoreCase) {
        a = a.toLowerCase();
        b = b.toLowerCase();
    }
    int aLength = a.length();
    int bLength = b.length();
    int minSize = Math.min(aLength, bLength);
    char aChar, bChar;
    boolean aNumber, bNumber;
    boolean asNumeric = false;
    int lastNumericCompare = 0;
    for (int i = 0; i < minSize; i++) {
        aChar = a.charAt(i);
        bChar = b.charAt(i);
        aNumber = aChar >= '0' && aChar <= '9';
        bNumber = bChar >= '0' && bChar <= '9';
        if (asNumeric)
            if (aNumber && bNumber) {
                if (lastNumericCompare == 0)
                    lastNumericCompare = aChar - bChar;
            } else if (aNumber)
                return 1;
            else if (bNumber)
                return -1;
            else if (lastNumericCompare == 0) {
                if (aChar != bChar)
                    return aChar - bChar;
                asNumeric = false;
            } else
                return lastNumericCompare;
        else if (aNumber && bNumber) {
            asNumeric = true;
            if (lastNumericCompare == 0)
                lastNumericCompare = aChar - bChar;
        } else if (aChar != bChar)
            return aChar - bChar;
    }
    if (asNumeric)
        if (aLength > bLength && a.charAt(bLength) >= '0' && a.charAt(bLength) <= '9') // as number
            return 1;  // a has bigger size, thus b is smaller
        else if (bLength > aLength && b.charAt(aLength) >= '0' && b.charAt(aLength) <= '9') // as number
            return -1;  // b has bigger size, thus a is smaller
        else
            return lastNumericCompare;
    else
        return aLength - bLength;
}
public static int naturalCompare(字符串a、字符串b、布尔ignoreCase){
如果(忽略案例){
a=a.toLowerCase();
b=b.toLowerCase();
}
int aLength=a.长度();
int bLength=b.长度();
int minSize=Math.min(aLength,bLength);
恰尔阿查尔;
布尔数a个数,b个数;
布尔值asNumeric=false;
int lastNumericCompare=0;
对于(int i=0;iaNumber=aChar>='0'&&aChar='0'&&bChar bLength&&a.charAt(bLength)>='0'&&a.charAt(bLength)aLength&&b.charAt(aLength)>='0'&&b.charAt(aLength)查找数字时,只需使用
lastIndexOf
子字符串(lastIndex+1)查找最后一个空格即可.
我认为正则表达式在这里太过分了。@Petar:我使用正则表达式是因为OP可能对他的示例进行了一些清理。只要您有一个稍微复杂的示例,您可能就需要正则表达式或一个完整的解析器。这是显示如何提取感兴趣的字段的一个更一般的答案,但正如您所说,对于这个确切的dat来说,它也太过分了a、 “fillupleftwithzero”可能重复?你能告诉我们它的代码吗?
public static int naturalCompare(String a, String b, boolean ignoreCase) {
    if (ignoreCase) {
        a = a.toLowerCase();
        b = b.toLowerCase();
    }
    int aLength = a.length();
    int bLength = b.length();
    int minSize = Math.min(aLength, bLength);
    char aChar, bChar;
    boolean aNumber, bNumber;
    boolean asNumeric = false;
    int lastNumericCompare = 0;
    for (int i = 0; i < minSize; i++) {
        aChar = a.charAt(i);
        bChar = b.charAt(i);
        aNumber = aChar >= '0' && aChar <= '9';
        bNumber = bChar >= '0' && bChar <= '9';
        if (asNumeric)
            if (aNumber && bNumber) {
                if (lastNumericCompare == 0)
                    lastNumericCompare = aChar - bChar;
            } else if (aNumber)
                return 1;
            else if (bNumber)
                return -1;
            else if (lastNumericCompare == 0) {
                if (aChar != bChar)
                    return aChar - bChar;
                asNumeric = false;
            } else
                return lastNumericCompare;
        else if (aNumber && bNumber) {
            asNumeric = true;
            if (lastNumericCompare == 0)
                lastNumericCompare = aChar - bChar;
        } else if (aChar != bChar)
            return aChar - bChar;
    }
    if (asNumeric)
        if (aLength > bLength && a.charAt(bLength) >= '0' && a.charAt(bLength) <= '9') // as number
            return 1;  // a has bigger size, thus b is smaller
        else if (bLength > aLength && b.charAt(aLength) >= '0' && b.charAt(aLength) <= '9') // as number
            return -1;  // b has bigger size, thus a is smaller
        else
            return lastNumericCompare;
    else
        return aLength - bLength;
}