NaturalSortingComparator.java
package com.tradecloud.domain.item;
import java.util.Comparator;
/**
* Created by IntelliJ IDEA.
* User: ds
* Date: 2013/07/29
* Time: 1:14 PM
* To change this template use File | Settings | File Templates.
*/
public class NaturalSortingComparator<T> implements Comparator<T> {
public NaturalSortingComparator() {
}
public boolean isDigit(char ch) {
return ch >= 48 && ch <= 57;
}
public String getChunk(NaturalStringSorting s, int slength, int marker) {
StringBuilder chunk = new StringBuilder();
char c = s.sortByString().charAt(marker);
chunk.append(c);
marker++;
if (isDigit(c)) {
while (marker < slength) {
c = s.sortByString().charAt(marker);
if (!isDigit(c)) break;
chunk.append(c);
marker++;
}
} else {
while (marker < slength) {
c = s.sortByString().charAt(marker);
if (isDigit(c)) break;
chunk.append(c);
marker++;
}
}
return chunk.toString();
}
@Override
public int compare(T o1, T o2) {
if (!(o1 instanceof NaturalStringSorting) || !(o2 instanceof NaturalStringSorting)) {
return 0;
}
NaturalStringSorting s1 = (NaturalStringSorting) o1;
NaturalStringSorting s2 = (NaturalStringSorting) o2;
int thisMarker = 0;
int thatMarker = 0;
int s1Length = s1.sortByString().length();
int s2Length = s2.sortByString().length();
while (thisMarker < s1Length && thatMarker < s2Length) {
String thisChunk = getChunk(s1, s1Length, thisMarker);
thisMarker += thisChunk.length();
String thatChunk = getChunk(s2, s2Length, thatMarker);
thatMarker += thatChunk.length();
// If both chunks contain numeric characters, sort them numerically
int result = 0;
if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0))) {
// Simple chunk comparison by length.
int thisChunkLength = thisChunk.length();
result = thisChunkLength - thatChunk.length();
// If equal, the first different number counts
if (result == 0) {
for (int i = 0; i < thisChunkLength; i++) {
result = thisChunk.charAt(i) - thatChunk.charAt(i);
if (result != 0) {
return result;
}
}
}
} else {
result = thisChunk.compareTo(thatChunk);
}
if (result != 0) return result;
}
return s1Length - s2Length;
}
}