Java/Kotlin 如何迭代字符串,以便组合字符与其基本字符保持一致?

Log*_*phy 3 java utf-16 kotlin

我正在尝试迭代以下字符串:

\n

m\xc9\x94\xcc\x83tr

\n

但无论我做什么,它总是最终被处理为:

\n

米 \xc9\x94 \xcc\x83 tr

\n

波形符似乎与反转的 c 分离。

\n

我的第一个尝试是执行以下操作:

\n
"m\xc9\x94\xcc\x83tr".map {\n    print(it)\n}\n
Run Code Online (Sandbox Code Playgroud)\n

但波形符不会与反转的 c 保持一致。

\n

我看到了以下迭代器的建议:

\n
fun codePoints(string: String): Iterable<String> {\n    return object : Iterable<String> {\n        override fun iterator(): MutableIterator<String> {\n            return object : MutableIterator<String> {\n                var nextIndex = 0\n                override fun hasNext(): Boolean {\n                    return nextIndex < string.length\n                }\n\n                override fun next(): String {\n                    val result = string.codePointAt(nextIndex)\n                    nextIndex += Character.charCount(result)\n                    return String(Character.toChars(result))\n                }\n\n                override fun remove() {\n                    throw UnsupportedOperationException()\n                }\n            }\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

但这给出了与前面的示例相同的输出。

\n

我已经被这个看似简单的问题困扰了一天,我只想处理这个字符串,就好像它有 4 个字符,而不是 5 个字符一样。

\n

有小费吗?

\n

Swe*_*per 11

“\xc9\x94\xcc\x83”由两个Unicode 代码点组成。这就是为什么您显示的代码点迭代器仍然将 \xc9\x94\xcc\x83 视为单独的。

\n

“\xc9\x94\xcc\x83”是单个字素簇。要迭代这些,您需要一个java.text.BreakIterator. 在文档中,有一个示例向您展示了如何操作。

\n
public static void printEachForward(BreakIterator boundary, String source) {\n    int start = boundary.first();\n    for (int end = boundary.next();\n         end != BreakIterator.DONE;\n         start = end, end = boundary.next()) {\n         System.out.println(source.substring(start,end));\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在 Kotlin 中,您可以编写一个扩展函数来String返回一个Sequence字素簇。

\n
fun String.graphemeClusterSequence() = sequence {\n    val iterator = BreakIterator.getCharacterInstance()\n    iterator.setText(this@graphemeClusterSequence)\n    var start = iterator.first()\n    var end = iterator.next()\n    while (end != BreakIterator.DONE) {\n        yield(this@graphemeClusterSequence.substring(start, end))\n        start = end\n        end = iterator.next()\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

现在"m\xc9\x94\xcc\x83tr".graphemeClusterSequence().forEach { println(it) }打印:

\n
m\n\xc9\x94\xcc\x83\nt\nr\n
Run Code Online (Sandbox Code Playgroud)\n