在 Java 中对 UTF-16 字符串中的字符进行排序

Sorting the characters in a UTF-16 string in Java

TLDR

Java用两个字符来表示UTF-16。使用 Arrays.sort (不稳定排序)会扰乱字符排序。我应该将 char[] 转换为 int[] 还是有更好的方法?

详情

Java表示一个字符为UTF-16。但是 Character class 本身包装了 char (16 位)。对于 UTF-16,它将是两个 char 的数组(32 位)。

使用内置排序对 UTF-16 字符串进行排序会使数据混乱。 (Arrays.sort 使用双枢轴快速排序,Collections.sort 使用 Arrays.sort 来完成繁重的工作。)

具体来说,你是把char[]转成int[]还是有更好的排序方式?

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] utfCodes = {128513, 128531, 128557};
        String emojis = new String(utfCodes, 0, 3);
        System.out.println("Initial String: " + emojis);

        char[] chars = emojis.toCharArray();
        Arrays.sort(chars);
        System.out.println("Sorted String: " + new String(chars));
    }
}

输出:

Initial String: 
Sorted String: ????

我环顾四周,找不到任何干净的方法来在不使用库的情况下通过两个元素的分组对数组进行排序。

幸运的是,StringcodePoints 是您在此示例中用来创建 String 本身的内容,因此您可以简单地对它们进行排序并创建一个新的 String 结果。

public static void main(String[] args) {
    int[] utfCodes = {128531, 128557, 128513};
    String emojis = new String(utfCodes, 0, 3);
    System.out.println("Initial String: " + emojis);

    int[] codePoints = emojis.codePoints().sorted().toArray();
    System.out.println("Sorted String: " + new String(codePoints, 0, 3));
}

Initial String:

Sorted String:

我调换了你例子中字符的顺序,因为它们已经排序了。

如果您使用 Java 8 或更高版本,那么这是一种在尊重(不破坏)多字符代码点的同时对字符串中的字符进行排序的简单方法:

int[] codepoints = someString.codePoints().sort().toArray();
String sorted = new String(codepoints, 0, codepoints.length);

在Java8之前,我认为你要么需要使用循环来迭代原始字符串中的代码点,要么使用第3方库方法。


幸运的是,对字符串中的代码点进行排序并不常见,因此上述解决方案的笨拙和相对低效很少成为问题。

(您最后一次测试表情符号的字谜是什么时候?)

我们不能将 char 用于 Unicode,because Java's Unicode char handling is broken

在 Java 的早期,Unicode 代码点总是 16 位(固定大小正好是一个字符)。但是,Unicode 规范更改为允许补充字符。这意味着 Unicode 字符现在是可变宽度的,并且可以长于一个字符。不幸的是,在不破坏大量生产代码的情况下更改 Java 的 char 实现为时已晚。

因此,操作 Unicode 字符的最佳方法是直接使用代码点,例如,在 JDK 1.8 及更高版本上使用 String.codePointAt(index)String.codePoints() 流。

其他来源: