从代码点整数列表生成字符串对象?

Posted

技术标签:

【中文标题】从代码点整数列表生成字符串对象?【英文标题】:Generate a String object from a List of code point integers? 【发布时间】:2021-10-06 21:36:16 【问题描述】:

如果我有一个 List< Integer > 其整数值是 Unicode code point 数字。如何构造由这些代码点确定的字符的String 对象?

例如:

List < Integer > codePoints = List.of( 100, 111, 103, 128054 ) ;

… 或:

List < Integer > codePoints = "cat".codePoints().boxed().toList();

我如何从codePoints 获得另一个值为catString 对象?

【问题讨论】:

好问题!正因为您使用了 Stream#toList,它可从 Java-16 获得,如果问题也被标记为 Java-16,它将对读者有用。 【参考方案1】:

ListStreamStringBuilderString

一种解决方案是将您的List 转换为Stream。然后将该流的元素收集到StringBuilder 中。 StringBuilder 类提供了一个 appendCodePoint 方法,专门用于容纳代码点整数。当可变的StringBuilder 完成后,转换为不可变的String

String output = codePoints.stream().collect( StringBuilder :: new , StringBuilder :: appendCodePoint , StringBuilder :: append ).toString();

或不同的格式:

String output = 
        codePoints
                .stream()
                .collect( StringBuilder :: new , StringBuilder :: appendCodePoint , StringBuilder :: append )
                .toString();

这是一些示例代码。

String input = "dog?" ;
List < Integer > codePoints = input.codePoints().boxed().collect( Collectors.toList() );  // In Java 16+, replace the last part with simply `.toList()`.
String output = 
        codePoints
                .stream()
                .collect( StringBuilder :: new , StringBuilder :: appendCodePoint , StringBuilder :: append )
                .toString();

看到这个code run live at IdeOne.com。

输入:狗?

代码点:[100、111、103、128054]

输出:狗?

要了解带有StringBuilder 方法引用的代码是如何工作的,请参阅Java 8 Int Stream collect with StringBuilder

为方便起见,我们可以为这段代码创建一个实用方法。为了安全起见,我们可以添加对.filter 的调用以跳过any invalid code point 号码(负数或超出Character.MAX_CODE_POINT)。

public static final String listOfCodePointsToString( List< Integer > codePoints )

    String output = 
            codePoints
                    .stream()
                    .filter( codePoint -> Character.isValidCodePoint​( codePoint ) )
                    .collect( StringBuilder :: new , StringBuilder :: appendCodePoint , StringBuilder :: append )
                    .toString();
    return output ;

看到code run live at IdeOne.com。

【讨论】:

your - 你不是说my吗?我一定是错过了什么。 @rzwitserloot 我不明白你的意思。 你在回答你自己的问题。 @rzwitserloot 是的,我以第二人称回答我自己的问题,以免分散读者的注意力。我写了问题和答案的事实是无关紧要的。我不知道你为什么会在意。【参考方案2】:

String has a constructor 接受 int 代码点编号的数组。

int[] ints = codePoints.stream().mapToInt(i -> i).toArray();
String string = new String(ints, 0, ints.length);

转换List -> Stream -> IntStream -> int[] -> String

【讨论】:

我不知道这个隐藏的宝藏,尽管它从 Java-5 开始就有了。【参考方案3】:

现有的答案很好,但也有一种简单的“老式”方法,不需要使用函数式接口或流。这是最小且完整的示例代码:

package cp2string;

import java.util.List;

public class CP2String 

    public static void main(String[] args) 
        List< Integer> codePoints = List.of(100, -999, 111, 103, 128054);
        Character BLACK_VERTICAL_RECTANGLE = '\u25AE';
        StringBuilder sb = new StringBuilder();

        for (int cp : codePoints) 
            sb.append(Character.toString(Character.isValidCodePoint(cp) ? cp : BLACK_VERTICAL_RECTANGLE));
        
        System.out.println("sb=" + sb.toString());
    

当代码运行时,输出如下:

sb=d▮og?

注意事项:

输出中的黑色矩形表示示例数据中故意包含的无效代码点。 静态方法Character.toString​(int codePoint)需要JDK 11或更高版本。 可能需要更改字体才能正确呈现输出。我使用了 Segoe UI 符号。 如果考虑并行操作,显然使用基于流的方法是可行的方法,但对于不关心性能和可伸缩性的场景,可以说简单的方法同样好。

【讨论】:

以上是关于从代码点整数列表生成字符串对象?的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 中加快字符串与对象的配对

关于一个javascript 产生随机数的function 的一点疑问 求教了~~

从相同索引的列表元素中选择随机整数并生成列表

从字符串数组中获取整数列表

从文字字符串生成编译时常量整数

7str字符串int整数list列表dict字典set集合tuple元祖功能详解