Number aware string sorting with comparator Java
Alphabetical gives: file1 file10 file2
- file1
- file10
- file2
What I'm calling "number aware" string sorting should give: file1 file2 file10
- file1
- file2
- file10
HereHere 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!
Number aware string sorting with comparator Java
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!
Number aware string sorting with comparator
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.
The code seems to work. Any cases where I could run into problem? If not any suggestions on making it simpler or more efficient.
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;
}
}
}
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;
}
}
}