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

- 2,290
- 1
- 18
- 29
-
Which is the order of sorting? – Abimaran Kugathasan Jan 17 '14 at 10:31
-
small to high as am expressed in question – J.K Jan 17 '14 at 10:32
-
wer12 should't be after abc12? – Typo Jan 17 '14 at 10:32
-
`abc2` is before `abc12`? – Abimaran Kugathasan Jan 17 '14 at 10:32
-
this is the order i need abc2,abc12,pqr23,pqr99,wer12,xyz3 – J.K Jan 17 '14 at 10:33
-
2Looks like duplicate - please see http://stackoverflow.com/questions/104599/sort-on-a-string-that-may-contain-a-number?rq=1 – Manvendra Gupta Jan 17 '14 at 10:33
-
Manvendra Gupta let me check – J.K Jan 17 '14 at 10:34
-
1what is the relative order of `ab1` and `abc1`according to your definition? – Boris Strandjev Jan 17 '14 at 10:35
-
I have to agree with @KugathasanAbimaran there's no explicit sort criteria (other tan small to high...small what to high what..?) – Typo Jan 17 '14 at 10:36
-
Boris Strandjev like that question ab1 can be first – J.K Jan 17 '14 at 10:39
-
how to use that algorithm duplicated question ? – J.K Jan 17 '14 at 10:46
3 Answers
If you have always the format (lettersNumbers
), you can use this regex (taken from here and slightly modified) :
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]

- 1
- 1

- 15,697
- 10
- 46
- 64
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.
Also, you might want to output them in the fashion of abc001
instead of abc1
since that would help your sorting immensly.
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?
So, whereever there is just 1 number pad it before with a 0.
But, inspite of that it is still doable and an easier solution than the comparator in my opinion

- 2,033
- 1
- 16
- 26
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);
}
}
}

- 31,165
- 11
- 75
- 105

- 3,294
- 4
- 29
- 41
-
5Can you please delete the copy pasted large class that brings no value to your answer? – Boris Strandjev Jan 17 '14 at 10:36