I have this class for use in sorting strings such that if strings have a number in the same position it will order the numbers in increasing order.
Alphabetical gives: file1 file10 file2
What I'm calling "number aware" string sorting should give: file1 file2 file10
Here is what I have using a regex split from there (http://stackoverflow.com/questions/8270784/how-to-split-a-string-between-letters-and-digits-or-between-digits-and-letters).
The code seems to work. Any cases where I could run into problem? If not any suggestions on making it simpler or more efficient.
Any help to improve the solution would be appreciated. Thanks!
import java.util.Comparator;
public class NumberAwareStringComparator implements Comparator<String>{
public int compare(String s1, String s2) {
String[] s1Parts = s1.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
String[] s2Parts = s2.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
int i = 0;
while(i < s1Parts.length && i < s2Parts.length){
//if parts are the same
if(s1Parts[i].compareTo(s2Parts[i]) == 0){
++i;
}else{
try{
int intS1 = Integer.parseInt(s1Parts[i]);
int intS2 = Integer.parseInt(s2Parts[i]);
//if the parse works
int diff = intS1 - intS2;
if(diff == 0){
++i;
}else{
return diff;
}
}catch(Exception ex){
return s1.compareTo(s2);
}
}//end else
}//end while
//Handle if one string is a prefix of the other.
// nothing comes before something.
if(s1.length() < s2.length()){
return -1;
}else if(s1.length() > s2.length()){
return 1;
}else{
return 0;
}
}
}
Thanks for the suggestions. Based on the suggestions and discussions I have changed the code to the following improved versions. I've take out //end ;) Any other suggestions? If not I'll mark rolfl's solution.
import java.util.Comparator;
import java.util.regex.Pattern;
public class NumberAwareStringComparator implements Comparator<String>{
private static Pattern BOUNDARYSPLIT = Pattern.compile("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
public int compare(String s1, String s2) {
String[] s1Parts = BOUNDARYSPLIT.split(s1);
String[] s2Parts = BOUNDARYSPLIT.split(s2);
int i = 0;
while(i < s1Parts.length && i < s2Parts.length){
//if parts are the same
if(s1Parts[i].compareTo(s2Parts[i]) == 0){
//go to next part
++i;
}else{
//check parts are both numeric
if(s1Parts[i].charAt(0) >= '0' && s1Parts[i].charAt(0) <= '9'
&& s2Parts[i].charAt(0) >= '0' && s2Parts[i].charAt(0) <= '9'){
try{
int intS1 = Integer.parseInt(s1Parts[i]);
int intS2 = Integer.parseInt(s2Parts[i]);
int diff = intS1 - intS2;
if(diff == 0){
++i;
}else{
return diff;
}
}catch(Exception ex){
//'should' never reach but ...
return s1Parts[i].compareTo(s2Parts[i]);
}
}else{
//string compare if neither are numeric
return s1Parts[i].compareTo(s2Parts[i]);
}
}
}
//Handle if one string is a prefix of the other.
// nothing comes before something.
if(s1.length() < s2.length()){
return -1;
}else if(s1.length() > s2.length()){
return 1;
}else{
return 0;
}
}
}
file1img
,file10img
,file2img
, you want them sortedfile1img
,file2img
,file10img
? If so, the pattern matched in your linked answer should work. Otherwise you should compare from the ends of the strings. – Trojan Dec 12 '13 at 7:24}//end while
If you need such comments to structure your code or make it more readable, there's something wrong with your code. – Bobby Dec 12 '13 at 13:04