在 Java 中對字母數字字串進行排序
1. 簡介
在處理數字和字母混合序列時,對字母數字字串進行排序是 Java 中的常見任務。這在檔案排序、資料庫索引和 UI 顯示格式化應用程式中特別有用。
在本教程中,我們將探索使用 Java 對字母數字字串和包含字母數字字串的陣列進行排序的不同方法。我們將從簡單的字典排序開始,然後轉向涉及字串陣列的更高級的自然排序技術。
2.問題定義
給定一個包含字母和數字的字串,我們的目標是對其進行排序同時保持邏輯順序。與純粹的字典排序相反,我們根據 ASCII 值將所有數字放在字母之前,更直觀的方法是將數值視為整數而不是單個數字。當我們有諸如對檔案名稱進行排序之類的用例時,這種區別變得尤為重要,即“file1”,“file10”,“file3”應按“file1”,“file3”,“file10”的順序排列。
為了簡單起見,在所有涉及字串陣列的情況下,我們都假設一種 ALPHANUMERIC 模式,這意味著每個字串的字母在前,數字在後。
我們將首先討論如何按字典順序對單個字母數字字串進行排序,從而探索不同的排序策略。然後,我們將轉向數組排序技術,該技術尊重自然數字順序和不區分大小寫。
3. 依字母順序(字典順序)對字串進行排序
最簡單的方法是將字串轉換為字元數組,然後使用 Java 的內建排序方法對其進行排序:
public static String lexicographicSort(String input) {
char[] stringChars = input.toCharArray();
Arrays.sort(stringChars);
return new String(stringChars);
}
在這裡,我們將一個字串作為輸入並根據 ASCII 對其進行排序,將數字放在大寫字母之前。我們可以使用以下字串作為輸入來測試我們的實作 - “C4B3A21”:
@Test void givenAlphanumericString_whenLexicographicSort_thenSortedLettersFirst() {
String stringToSort = "C4B3A21";
String sorted = AlphanumericSort.lexicographicSort(stringToSort);
assertThat(sorted).isEqualTo("1234ABC");
}
如上所示,我們得到了按“1234ABC”排序的輸出,正如我們預期的那樣。雖然對於基本排序有效,但此方法不將數字作為整數值處理,從而導致檔案名稱等情況下的排序不正確。
4. 自然字母數字順序的自訂排序
為了解決按字典順序排序將數字視為單一字元的問題,我們引入了一個自訂Comparator
,可以正確提取和比較數值:
public static String[] naturalAlphanumericSort(String[] arrayToSort) {
Arrays.sort(arrayToSort, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return extractInt(s1) - extractInt(s2);
}
private int extractInt(String str) {
String num = str.replaceAll("\\D+", "");
return num.isEmpty() ? 0 : Integer.parseInt(num);
}
});
return arrayToSort;
}
我們作為輸入的字串陣列首先提取數字值,並使用extractInt()
輔助方法刪除所有非數字字元。提取的整數之間的差異決定了它們的順序。我們可以看到,對於一個假設的檔案名稱列表,其中字母位於數字之前,我們得到一個自然的排序:
@Test
void givenAlphanumericArrayOfStrings_whenNaturalAlphanumericSort_thenSortNaturalOrder() {
String[] arrayToSort = {"file2", "file10", "file0", "file1", "file20"};
String[] sorted = AlphanumericSort.naturalAlphanumericSort(arrayToSort);
assertThat(Arrays.toString(sorted)).isEqualTo("[file0, file1, file2, file10, file20]");
}
透過這種方法,我們可以確保排序是按數字而不是字典順序進行的。但是,它不處理大小寫變化,我們將在下一節中討論。
5. 對大小寫字母數字字串進行排序
為了解決不區分大小寫的排序場景,同時仍保持字母數字順序,我們改進了Comparator
:
public static String[] naturalAlphanumericCaseInsensitiveSort(String[] arrayToSort) {
Arrays.sort(arrayToSort, Comparator.comparing((String s) -> s.replaceAll("\\d", "").toLowerCase())
.thenComparingInt(s -> {
String num = s.replaceAll("\\D+", "");
return num.isEmpty() ? 0 : Integer.parseInt(num);
}).thenComparing(Comparator.naturalOrder()));
return arrayToSort;
}
在這個實作中,我們首先比較非數字前綴(忽略大小寫),以不區分大小寫的自然順序對字母數字字串數組進行排序,然後按數字部分(作為整數而不是按字元)對字串進行排序,最後,我們使用字典順序作為決勝局,以保留字串的原始大小寫順序。
我們也用適當的輸入來測試我們的解決方案:
@Test
void givenAlphanumericArrayOfStrings_whenAlphanumericCaseInsensitiveSort_thenSortNaturalOrder() {
String[] arrayToSort = {"a2", "A10", "b1", "B3", "A2"};
String[] sorted = AlphanumericSort.naturalAlphanumericCaseInsensitiveSort(arrayToSort);
assertThat(Arrays.toString(sorted)).isEqualTo("[A2, a2, A10, b1, B3]");
}
我們獲得一個正確排序的字串數組,其中字元部分按適當順序排序,後面跟著按自然順序排列的數值。
6. 結論
我們探索了在 Java 中對字母數字字串進行排序的三種方法,從基本的字典排序到使用自訂比較器和混合大小寫處理的自然排序。最佳方法取決於特定要求,例如效能、順序約束以及是否允許重複值。
本文的完整原始碼可以在 GitHub 上找到。