Natural sorting, for digits use value (01 -> 1), order by leading zeros (1 > 01)

Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
This commit is contained in:
tobiasKaminsky 2018-03-01 12:00:07 +01:00 committed by AndyScherzinger
parent 6b000595b1
commit c5d492cee9
No known key found for this signature in database
GPG key ID: 6CADC7E3523C308B
2 changed files with 53 additions and 14 deletions

View file

@ -27,6 +27,7 @@ package third_parties.daveKoeller;
import com.owncloud.android.datamodel.OCFile;
import java.io.File;
import java.io.Serializable;
import java.text.Collator;
import java.util.Comparator;
import java.util.Locale;
@ -47,7 +48,7 @@ import java.util.Locale;
* https://github.com/nextcloud/server/blob/9a4253ef7c34f9dc71a6a9f7828a10df769f0c32/tests/lib/NaturalSortTest.php
* by Tobias Kaminsky
*/
public class AlphanumComparator<T> implements Comparator<T> {
public class AlphanumComparator<T> implements Comparator<T>, Serializable {
private boolean isDigit(char ch) {
return ch >= 48 && ch <= 57;
}
@ -120,17 +121,48 @@ public class AlphanumComparator<T> implements Comparator<T> {
// 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;
// extract digits
int thisChunkZeroCount = 0;
boolean zero = true;
int c = 0;
while (c < (thisChunk.length()) && isDigit(thisChunk.charAt(c))) {
if (zero) {
if (Character.getNumericValue(thisChunk.charAt(c)) == 0) {
thisChunkZeroCount++;
} else {
zero = false;
}
}
c++;
}
int thisChunkValue = Integer.parseInt(thisChunk.substring(0, c));
int thatChunkZeroCount = 0;
c = 0;
zero = true;
while (c < (thatChunk.length()) && isDigit(thatChunk.charAt(c))) {
if (zero) {
if (Character.getNumericValue(thatChunk.charAt(c)) == 0) {
thatChunkZeroCount++;
} else {
zero = false;
}
}
c++;
}
int thatChunkValue = Integer.parseInt(thatChunk.substring(0, c));
result = Integer.compare(thisChunkValue, thatChunkValue);
if (result == 0) {
// value is equal, compare leading zeros
result = Integer.compare(thisChunkZeroCount, thatChunkZeroCount);
if (result != 0) {
return result;
}
} else {
return result;
}
} else if (isSpecialChar(thisChunk.charAt(0)) && isSpecialChar(thatChunk.charAt(0))) {
for (int i = 0; i < thisChunk.length(); i++) {

View file

@ -43,10 +43,10 @@ public class TestSorting {
@Test
public void testSpecialChars() {
String[] unsortedArray = {"11 - November", "Test 04", "Test 01", "Ôle", "Üüü", "01 - Januar", "[Test] Folder",
String[] unsortedArray = {"Test 1", "11 - November", "Test 04", "Test 01", "Ôle", "Üüü", "01 - January", "[Test] Folder",
"z.[Test]", "z. Test"};
String[] sortedArray = {"[Test] Folder", "01 - Januar", "11 - November", "Ôle", "Test 01", "Test 04", "Üüü",
String[] sortedArray = {"[Test] Folder", "01 - January", "11 - November", "Ôle", "Test 1", "Test 01", "Test 04", "Üüü",
"z. Test", "z.[Test]"};
assertTrue(sortAndTest(unsortedArray, sortedArray));
@ -60,6 +60,14 @@ public class TestSorting {
assertTrue(sortAndTest(unsortedArray, sortedArray));
}
@Test
public void testTrailingZeros() {
String[] unsortedArray = {"T 3 abc", "T 2 abc", "T 03 abc", "T 01 abc", "T 0 abc", "T 02 abc", "T 1 abc", "T 001 abc", "T 000 abc", "T 00 abc"};
String[] sortedArray = {"T 0 abc", "T 00 abc", "T 000 abc", "T 1 abc", "T 01 abc", "T 001 abc", "T 2 abc", "T 02 abc", "T 3 abc", "T 03 abc"};
assertTrue(sortAndTest(unsortedArray, sortedArray));
}
@Test
public void testNumbers() {
String[] unsortedArray = {"124.txt", "abc1", "123.txt", "abc", "abc2", "def (2).txt", "ghi 10.txt", "abc12",
@ -99,7 +107,7 @@ public class TestSorting {
List<String> sortedList = Arrays.asList(sortedArray);
Collections.sort(unsortedList, new AlphanumComparator());
Collections.sort(unsortedList, new AlphanumComparator<>());
for (int i = 0; i < sortedList.size(); i++) {
if (sortedList.get(i).compareTo(unsortedList.get(i)) != 0) {
@ -107,7 +115,6 @@ public class TestSorting {
System.out.println(" target: " + sortedList.toString());
System.out.println(" actual: " + unsortedList.toString());
return false;
}
}