mirror of
https://github.com/mitb-archive/filebot
synced 2024-08-13 17:03:45 -04:00
b1a30e4bc3
@see https://www.filebot.net/forums/viewtopic.php?f=10&t=4174 @see http://stackoverflow.com/questions/12640280/looking-for-a-combination-of-alphabetical-and-natural-order-aka-user-sane-sort
105 lines
2.6 KiB
Java
105 lines
2.6 KiB
Java
package net.filebot.util;
|
|
|
|
import java.text.Collator;
|
|
import java.util.Comparator;
|
|
import java.util.Locale;
|
|
|
|
public class AlphanumComparator implements Comparator<String> {
|
|
|
|
protected Collator collator;
|
|
|
|
public AlphanumComparator(Collator collator) {
|
|
this.collator = collator;
|
|
}
|
|
|
|
public AlphanumComparator(Locale locale) {
|
|
this.collator = Collator.getInstance(locale);
|
|
this.collator.setDecomposition(Collator.FULL_DECOMPOSITION);
|
|
this.collator.setStrength(Collator.PRIMARY);
|
|
}
|
|
|
|
protected boolean isDigit(String s, int i) {
|
|
return Character.isDigit(s.charAt(i));
|
|
}
|
|
|
|
protected int getNumericValue(String s, int i) {
|
|
return Character.getNumericValue(s.charAt(i));
|
|
}
|
|
|
|
protected String getChunk(String s, int start) {
|
|
int index = start;
|
|
int length = s.length();
|
|
boolean mode = isDigit(s, index++);
|
|
|
|
while (index < length) {
|
|
if (mode != isDigit(s, index)) {
|
|
break;
|
|
}
|
|
|
|
++index;
|
|
}
|
|
|
|
return s.substring(start, index);
|
|
}
|
|
|
|
public int compare(String s1, String s2) {
|
|
int length1 = s1.length();
|
|
int length2 = s2.length();
|
|
int index1 = 0;
|
|
int index2 = 0;
|
|
int result = 0;
|
|
|
|
while (result == 0 && index1 < length1 && index2 < length2) {
|
|
String chunk1 = getChunk(s1, index1);
|
|
index1 += chunk1.length();
|
|
|
|
String chunk2 = getChunk(s2, index2);
|
|
index2 += chunk2.length();
|
|
|
|
if (isDigit(chunk1, 0) && isDigit(chunk2, 0)) {
|
|
int chunkLength1 = chunk1.length();
|
|
int chunkLength2 = chunk2.length();
|
|
|
|
// count and skip leading zeros
|
|
int zeroIndex1 = 0;
|
|
while (zeroIndex1 < chunkLength1 && getNumericValue(chunk1, zeroIndex1) == 0) {
|
|
++zeroIndex1;
|
|
}
|
|
|
|
// count and skip leading zeros
|
|
int zeroIndex2 = 0;
|
|
while (zeroIndex2 < chunkLength2 && getNumericValue(chunk2, zeroIndex2) == 0) {
|
|
++zeroIndex2;
|
|
}
|
|
|
|
// the longer run of non-zero digits is greater
|
|
result = (chunkLength1 - zeroIndex1) - (chunkLength2 - zeroIndex2);
|
|
|
|
// if the length is the same, the first differing digit decides
|
|
// which one is deemed greater.
|
|
int numberIndex1 = zeroIndex1;
|
|
int numberIndex2 = zeroIndex2;
|
|
|
|
while (result == 0 && numberIndex1 < chunkLength1 && numberIndex2 < chunkLength2) {
|
|
result = getNumericValue(chunk1, numberIndex1++) - getNumericValue(chunk2, numberIndex2++);
|
|
}
|
|
|
|
// if still no difference, the longer zeros-prefix is greater
|
|
if (result == 0) {
|
|
result = numberIndex1 - numberIndex2;
|
|
}
|
|
} else {
|
|
result = collator.compare(chunk1, chunk2);
|
|
}
|
|
}
|
|
|
|
// if there was no difference at all, let the longer one be the greater one
|
|
if (result == 0) {
|
|
result = length1 - length2;
|
|
}
|
|
|
|
// limit result to (-1, 0, or 1)
|
|
return Integer.signum(result);
|
|
}
|
|
|
|
} |