Java 的 String.compareTo 使用 UTF16 排序顺序。
List<String> inputValues = Arrays.asList("𝐴","figure", "flagship", "zion");
Collections.sort(inputValues);
以上代码结果已排序
[zion, 𝐴, figure, flagship]
但是,我希望这个排序顺序是[zion, figure, flagship, 𝐴]
请注意,某些字符是连字。
使用排序:
Collections.sort(keywordsList, new UTF8Comparator());
并创建自定义 UTF8 比较器:
class UTF8Comparator implements Comparator<String> {
@Override
public int compare(String str1, String str2) {
byte[] bytes1 = str1.getBytes(java.nio.charset.StandardCharsets.UTF_8);
byte[] bytes2 = str2.getBytes(java.nio.charset.StandardCharsets.UTF_8);
for (int i = 0; i < Math.min(bytes1.length, bytes2.length); i++) {
if (bytes1[i] != bytes2[i]) {
return bytes1[i] - bytes2[i];
}
}
return bytes1.length - bytes2.length;
}
}
抱歉,我不是在寻找字典排序,而是简单地基于 Unicode 代码点(UTF-8 或 UTF-32)进行排序。
我正在尝试使用的库之一中有一条评论:
输入值(键)。这些必须以 Unicode 代码点(UTF8 或 UTF32)排序顺序提供给 Builder。请注意,按 Java 的 String.compareTo(UTF16 排序顺序)进行排序是不正确的,并且可能会在构建 FST 时导致异常
我遇到了问题,因为我使用的是
Collections.sort
,它是 Java 的 UTF-16 排序顺序。最后我编写了自己的比较函数,如下所示,它解决了我面临的问题。令我惊讶的是,它本身不可用,也不能与其他一些流行的库一起使用。
public static void sort(List<String> list) {
Collections.sort(
list,
new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
int n1 = s1.length();
int n2 = s2.length();
int min = Math.min(n1, n2);
for (int i = 0; i < min; i++) {
int c1 = s1.codePointAt(i);
int c2 = s2.codePointAt(i);
if (c1 != c2) {
return c1 - c2;
}
}
return n1 - n2;
}
});
}
【可能大家没有注意到,看似大写的
A
其实是:
Mathematical Italic Capital A (U+1D434)
]
您的问题是,在 Java 中,BMP 之外的字符被编码为两个字符。
要根据代码点字典顺序对列表进行排序,您需要定义自己的
Comparator
:
public class CodePointComparator implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
int len1 = o1.length();
int len2 = o2.length();
int lim = Math.min(len1, len2);
int k = 0;
while (k < lim) {
char c1 = o1.charAt(k);
char c2 = o2.charAt(k);
if (c1 != c2) {
// A high surrogate is greater than a non-surrogate character
if (Character.isHighSurrogate(c1) != Character.isHighSurrogate(c2)) {
return Character.isHighSurrogate(c1) ? 1 : -1;
}
return c1 - c2;
}
k++;
}
return len1 - len2;
}
}
并将其作为参数传递给
List#sort
方法。我直接对代理对进行操作以获得一些性能。
最简单的方法:
inputValues.sort(String.CASE_INSENSITIVE_ORDER.reversed());
有点复杂,但有更多控制:
将列表转换为数组:
String[] arr = new String[inputValues .size()];
for (int i =0; i < inputValues .size(); i++)
arr[i] = inputValues.get(i);
还有其他有效的方法将列表转换为数组,但这是最容易理解的!
然后使用这个功能:
public static String[] textSort(String[] words) {
for (int i = 0; i < words.length; i++) {
for (int j = i + 1; j < words.length; j++) {
if (words[i].toUpperCase().compareTo(words[j].toUpperCase()) < 0) {//change this to > if you want to sort reverse order
String temp = words[i];
words[i] = words[j];
words[j] = temp;
}
}
}
return words;
}