How can i sort strings contains numbers in java ? Example : abc12,abc2,xyz3,pqr23,pqr99,wer12
need to get abc2,abc12,pqr23,pqr99,wer12
i tried with comparator but can only compare that of numbers need to compare both strings and numbers . please help me. Thanks
如何在java中对包含数字的字符串进行排序?例如:abc12,abc2,xyz3,pqr23,pqr99,wer12需要得到abc2,abc12,pqr23,pqr99,wer12我尝试用比较器但只能比较数字需要比较字符串和数字。请帮我。谢谢
3 个解决方案
#1
2
If you have always the format (lettersNumbers
), you can use this regex (taken from here and slightly modified) :
如果您始终使用格式(lettersNumbers),则可以使用此正则表达式(从此处获取并略微修改):
private static final String PATTERN = "[^a-z0-9]+|(?<=[a-z])(?=[0-9])|(?<=[0-9])(?=[a-z])";
public static void main(String[] args) {
List<String> l = Arrays.asList("abc12","abc2","xyz3","pqr23","pqr99","wer12");
Collections.sort(l, new Comparator<String>(){
@Override
public int compare(String arg0, String arg1) {
String [] arr0 = arg0.split(PATTERN);
String [] arr1 = arg1.split(PATTERN);
int cmp = arr0[0].compareTo(arr1[0]);
return cmp != 0 ? cmp : Integer.compare(Integer.parseInt(arr0[1]), Integer.parseInt(arr1[1]));
}
});
System.out.println(l);
}
Output :
[abc2, abc12, pqr23, pqr99, wer12, xyz3]
#2
1
Use natural sorting:
使用自然分类:
package org.cougaar.util;
import java.util.Comparator;
/**
* A sorting comparator to sort strings numerically,
* ie [1, 2, 10], as opposed to [1, 10, 2].
*/
public final class NaturalOrderComparator<T> implements Comparator<T> {
public static final Comparator<String> NUMERICAL_ORDER = new NaturalOrderComparator<String>(false);
public static final Comparator<String> CASEINSENSITIVE_NUMERICAL_ORDER = new NaturalOrderComparator<String>(true);
private final boolean caseInsensitive;
private NaturalOrderComparator(boolean caseInsensitive) {
this.caseInsensitive = caseInsensitive;
}
int compareRight(String a, String b) {
int bias = 0;
int ia = 0;
int 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 (!Character.isDigit(ca) && !Character.isDigit(cb)) {
return bias;
} else if (!Character.isDigit(ca)) {
return -1;
} else if (!Character.isDigit(cb)) {
return +1;
} else if (ca < cb) {
if (bias == 0) {
bias = -1;
}
} else if (ca > cb) {
if (bias == 0)
bias = +1;
} else if (ca == 0 && cb == 0) {
return bias;
}
}
}
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) {
// 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 zeros
while (ca == '0') {
if (ca == '0') {
nza++;
} else {
// only count consecutive zeroes
nza = 0;
}
// if the next character isn't a digit, then we've had a run of only zeros
// we still need to treat this as a 0 for comparison purposes
if (!Character.isDigit(charAt(a, ia+1)))
break;
ca = charAt(a, ++ia);
}
while (cb == '0') {
if (cb == '0') {
nzb++;
} else {
// only count consecutive zeroes
nzb = 0;
}
// if the next character isn't a digit, then we've had a run of only zeros
// we still need to treat this as a 0 for comparison purposes
if (!Character.isDigit(charAt(b, ib+1)))
break;
cb = charAt(b, ++ib);
}
// process run of digits
if (Character.isDigit(ca) && Character.isDigit(cb)) {
if ((result = compareRight(a.substring(ia), b
.substring(ib))) != 0) {
return result;
}
}
if (ca == 0 && cb == 0) {
// The strings compare the same. Perhaps the caller
// will want to call strcmp to break the tie.
return nza - nzb;
}
if (ca < cb) {
return -1;
} else 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);
}
}
}
#3
1
EDIT
One way of doing it in a simplistic manner would be pad the numbers with preceeding zeroes. so, say if you have strings such as
以简单方式执行此操作的一种方法是使用前面的零填充数字。所以,如果你有字符串,比如说
abc1
abc10
abc100
You parse your strings and pad the strings which have numbers occupy the same space. so your strings would become
您解析字符串并填充具有数字占用相同空间的字符串。所以你的字符串会变成
abc001
abc010
abc100
Now, just sort them, and the natural ordering should sort them beautifully without a hassle.
现在,只需对它们进行排序,自然排序应该可以毫不费力地对它们进行排序。
This is all provided you have a knowledge of how many numbers will constitute the part of the String.
如果你知道有多少数字将构成String的一部分,那么这就是全部。
Also, you might want to output them in the fashion of abc001
instead of abc1
since that would help your sorting immensly.
此外,您可能希望以abc001而不是abc1的方式输出它们,因为这将有助于您的排序。
Can you not parse and update your strings to be from say abc2
to abc02
If you do that, the sorting after that would just work fine. isnt it?
难道你不能解析和更新你的字符串从abc2到abc02如果这样做,那之后的排序就可以了。不是吗?
So, whereever there is just 1 number pad it before with a 0.
所以,只要有一个数字填充它之前只有0。
But, inspite of that it is still doable and an easier solution than the comparator in my opinion
但是,尽管如此,我认为它仍然可行,而且比对手更容易解决
#1
2
If you have always the format (lettersNumbers
), you can use this regex (taken from here and slightly modified) :
如果您始终使用格式(lettersNumbers),则可以使用此正则表达式(从此处获取并略微修改):
private static final String PATTERN = "[^a-z0-9]+|(?<=[a-z])(?=[0-9])|(?<=[0-9])(?=[a-z])";
public static void main(String[] args) {
List<String> l = Arrays.asList("abc12","abc2","xyz3","pqr23","pqr99","wer12");
Collections.sort(l, new Comparator<String>(){
@Override
public int compare(String arg0, String arg1) {
String [] arr0 = arg0.split(PATTERN);
String [] arr1 = arg1.split(PATTERN);
int cmp = arr0[0].compareTo(arr1[0]);
return cmp != 0 ? cmp : Integer.compare(Integer.parseInt(arr0[1]), Integer.parseInt(arr1[1]));
}
});
System.out.println(l);
}
Output :
[abc2, abc12, pqr23, pqr99, wer12, xyz3]
#2
1
Use natural sorting:
使用自然分类:
package org.cougaar.util;
import java.util.Comparator;
/**
* A sorting comparator to sort strings numerically,
* ie [1, 2, 10], as opposed to [1, 10, 2].
*/
public final class NaturalOrderComparator<T> implements Comparator<T> {
public static final Comparator<String> NUMERICAL_ORDER = new NaturalOrderComparator<String>(false);
public static final Comparator<String> CASEINSENSITIVE_NUMERICAL_ORDER = new NaturalOrderComparator<String>(true);
private final boolean caseInsensitive;
private NaturalOrderComparator(boolean caseInsensitive) {
this.caseInsensitive = caseInsensitive;
}
int compareRight(String a, String b) {
int bias = 0;
int ia = 0;
int 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 (!Character.isDigit(ca) && !Character.isDigit(cb)) {
return bias;
} else if (!Character.isDigit(ca)) {
return -1;
} else if (!Character.isDigit(cb)) {
return +1;
} else if (ca < cb) {
if (bias == 0) {
bias = -1;
}
} else if (ca > cb) {
if (bias == 0)
bias = +1;
} else if (ca == 0 && cb == 0) {
return bias;
}
}
}
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) {
// 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 zeros
while (ca == '0') {
if (ca == '0') {
nza++;
} else {
// only count consecutive zeroes
nza = 0;
}
// if the next character isn't a digit, then we've had a run of only zeros
// we still need to treat this as a 0 for comparison purposes
if (!Character.isDigit(charAt(a, ia+1)))
break;
ca = charAt(a, ++ia);
}
while (cb == '0') {
if (cb == '0') {
nzb++;
} else {
// only count consecutive zeroes
nzb = 0;
}
// if the next character isn't a digit, then we've had a run of only zeros
// we still need to treat this as a 0 for comparison purposes
if (!Character.isDigit(charAt(b, ib+1)))
break;
cb = charAt(b, ++ib);
}
// process run of digits
if (Character.isDigit(ca) && Character.isDigit(cb)) {
if ((result = compareRight(a.substring(ia), b
.substring(ib))) != 0) {
return result;
}
}
if (ca == 0 && cb == 0) {
// The strings compare the same. Perhaps the caller
// will want to call strcmp to break the tie.
return nza - nzb;
}
if (ca < cb) {
return -1;
} else 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);
}
}
}
#3
1
EDIT
One way of doing it in a simplistic manner would be pad the numbers with preceeding zeroes. so, say if you have strings such as
以简单方式执行此操作的一种方法是使用前面的零填充数字。所以,如果你有字符串,比如说
abc1
abc10
abc100
You parse your strings and pad the strings which have numbers occupy the same space. so your strings would become
您解析字符串并填充具有数字占用相同空间的字符串。所以你的字符串会变成
abc001
abc010
abc100
Now, just sort them, and the natural ordering should sort them beautifully without a hassle.
现在,只需对它们进行排序,自然排序应该可以毫不费力地对它们进行排序。
This is all provided you have a knowledge of how many numbers will constitute the part of the String.
如果你知道有多少数字将构成String的一部分,那么这就是全部。
Also, you might want to output them in the fashion of abc001
instead of abc1
since that would help your sorting immensly.
此外,您可能希望以abc001而不是abc1的方式输出它们,因为这将有助于您的排序。
Can you not parse and update your strings to be from say abc2
to abc02
If you do that, the sorting after that would just work fine. isnt it?
难道你不能解析和更新你的字符串从abc2到abc02如果这样做,那之后的排序就可以了。不是吗?
So, whereever there is just 1 number pad it before with a 0.
所以,只要有一个数字填充它之前只有0。
But, inspite of that it is still doable and an easier solution than the comparator in my opinion
但是,尽管如此,我认为它仍然可行,而且比对手更容易解决