作者:他给我留下的美好_813 | 来源:互联网 | 2024-12-15 17:25
在Java编程中,处理包含数字的字符串时,标准的字符串排序方法可能会导致不符合直观预期的结果,例如,"A2"会出现在"A10"之前。为了解决这个问题,可以通过实现一个自定义的比较器来达到自然排序的效果。
/**
* 实现自然排序的比较器
*/
public final class NaturalOrderComparator implements Comparator {
private final boolean caseInsensitive;
public NaturalOrderComparator(boolean caseInsensitive) {
this.caseInsensitive = caseInsensitive;
}
private int compareRight(String a, String b) {
int bias = 0;
int ia = 0, ib = 0;
while (true) {
char ca = charAt(a, ia);
char cb = charAt(b, ib);
if (!Character.isDigit(ca) && !Character.isDigit(cb)) {
return bias;
}
if (!Character.isDigit(ca)) {
return -1;
}
if (!Character.isDigit(cb)) {
return +1;
}
if (ca if (bias == 0) {
bias = -1;
}
}
if (ca > cb) {
if (bias == 0) {
bias = +1;
}
}
if (ca == 0 && cb == 0) {
return bias;
}
ia++;
ib++;
}
}
@Override
public int compare(T o1, T o2) {
String a = o1.toString();
String b = o2.toString();
int ia = 0, ib = 0;
int nza = 0, nzb = 0;
char ca, cb;
int result;
while (true) {
nza = nzb = 0;
ca = charAt(a, ia);
cb = charAt(b, ib);
while (ca == '0') {
nza++;
if (!Character.isDigit(charAt(a, ia + 1))) {
break;
}
ca = charAt(a, ++ia);
}
while (cb == '0') {
nzb++;
if (!Character.isDigit(charAt(b, ib + 1))) {
break;
}
cb = charAt(b, ++ib);
}
if (Character.isDigit(ca) && Character.isDigit(cb)) {
if ((result = compareRight(a.substring(ia), b.substring(ib))) != 0) {
return result;
}
}
if (ca == 0 && cb == 0) {
return nza - nzb;
}
if (ca return -1;
}
if (ca > cb) {
return +1;
}
ia++;
ib++;
}
}
private char charAt(String s, int i) {
if (i >= s.length()) {
return 0;
} else {
return caseInsensitive ? Character.toUpperCase(s.charAt(i)) : s.charAt(i);
}
}
}
下面是一个使用上述比较器对列表进行排序的例子:
public class Test {
public static void main(String[] args) {
List list = new ArrayList<>();
list.add("A1");
list.add("A2");
list.add("A40");
list.add("A10");
list.add("A110");
list.add("A112");
list.add("A3");
list.add("A04");
Collections.sort(list, new NaturalOrderComparator<>(true));
list.forEach(System.out::println);
}
}
运行上述代码后,输出结果将如下所示:
A1
A2
A3
A04
A10
A40
A110
A112