在 Kotlin 中,是否有更好的方法将代码点流转换为字符串?

Is there a better way to convert a stream of code points into a string in Kotlin?

我有一个代码点序列 Sequence<Int>

我想把它变成 String

我目前做的是:

val string = codePoints
    .map { codePoint -> String(intArrayOf(codePoint), 0, 1) }
    .joinToString()

但是为每个代码点创建一个字符串只是为了在之后立即连接它们感觉非常麻烦。 有更直接的方法吗?

到目前为止,我能做的最好的事情是这样的:

val string2 = codePoints.toList().toIntArray()
    .let { codePoints -> String(codePoints, 0, codePoints.size) }

代码量也好不到哪里去,而且它有一个 toList().toIntArray() 我不是很喜欢。但至少避免了把所有东西都打包成几十个单码字符串,逻辑还是按逻辑顺序写的

val result = codePoints.map { Character.toString(it) }.joinToString("")

编辑,根据下面 Joffrey 的评论:

val result = codePoints.joinToString("") { Character.toString(it) }

补充编辑,完整示例:

val codePoints: Sequence<Int> = sequenceOf(
  'a'.code,
  Character.toCodePoint(0xD83D.toChar(), 0xDE03.toChar()),
  Character.toCodePoint(0xD83D.toChar(), 0xDE04.toChar()),
  Character.toCodePoint(0xD83D.toChar(), 0xDE05.toChar())
)

val result = codePoints.joinToString("") { Character.toString(it) }

println(result)

这将打印:a

你可以选择简单的:

val string = codePoints.joinToString("") { Character.toString(it) }
// or
val string = codePoints.joinToString("", transform = Character::toString)

或使用字符串生成器:

fun Sequence<Int>.codePointsToString(): String = buildString {
    this@codePointsToString.forEach { cp ->
        appendCodePoint(cp)
    }
}

第二个完全表达了您想要的内容,并且可能会受益于字符串构建器中未来的优化。

it feels extremely hairy to create a string for each code point just to concatenate them immediately after

您是否真的测量了此处创建的额外字符串对象的性能问题?使用 toList() 还会在幕后创建一堆对象数组(每次调整大小一个),这会少一些,但不会好得多。正如您所指出的 toIntArray 最重要的是另一个数组创建。

除非你预先知道序列中的元素数量,否则我认为你对此无能为力(字符串生成器方法也可能在幕后使用可调整大小的数组,但至少你不需要额外的阵列副本)。