Browse Source

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

Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
tobiasKaminsky 7 years ago
parent
commit
c5d492cee9

+ 42 - 10
src/main/java/third_parties/daveKoeller/AlphanumComparator.java

@@ -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++) {

+ 11 - 4
src/test/java/com/owncloud/android/utils/TestSorting.java

@@ -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;
             }
         }