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

din*_*ngy 16 java sorting string utf-16

TLDR

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

细节

Java将字符表示为UTF-16。但是Character类本身会包装char(16位)。对于UTF-16,它将是2的数组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));
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

Initial String: 
Sorted String: ????
Run Code Online (Sandbox Code Playgroud)

Jac*_* G. 12

我四处张望,没有找到任何干净的方法来对两个元素进行分组来对数组进行排序,而不使用库。

幸运的是,codePoints中的String就是您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));
}
Run Code Online (Sandbox Code Playgroud)

初始字符串:

排序字符串:

因为您已经对它们进行了排序,所以我在示例中切换了字符的顺序。

  • @dingy Java 8是EOL。您需要迁移到Java 12。 (4认同)
  • 自Java 5以来,就一直存在Codepoint支持。只有Stream API才使它看起来几乎是一排,需要Java 8或更高版本。 (3认同)

Ste*_*n C 6

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

int[] codepoints = someString.codePoints().sort().toArray();
String sorted = new String(codepoints, 0, codepoints.length);
Run Code Online (Sandbox Code Playgroud)

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


幸运的是,对字符串中的代码点进行排序并不常见,以至于上述解决方案的笨拙和相对效率低下很少引起关注。

(您上次测试表情符号字谜是什么时候?)

  • 为了增加火焰,单个表情符号可能包含多个代码点。例如‍♀️由*五个*代码点(七个`char`s)组成。但是,即使是拉丁字符也可能由多个代码点组成。 (4认同)