1

CJK ExtB プランの Unicode 文字を含む Java 文字列を Decimal NCR に変換しようとしています。

例 ( http://people.w3.org/rishida/tools/conversion/で試すことができます):

  • 「游鍚堃」はに変換する必要があります游鍚堃
  • 「懷」はに変換する必要があります𧦧懷

これが私が試したものです(Scalaで):

def charToHex(char: Char) = "&#%d;" format(char.toInt)
def stringToHex (string: String) = string.flatMap(charToHex)

println (stringToHex("游鍚堃")) // 游鍚堃
println (stringToHex("懷"))   // ��懷
println ("懷".toCharArray().length) // Why it is 3?

ご覧のとおり、最初のケースでは 3 つの Unicode 文字が 3 つの NCR に正しく変換されます。

しかし、2 番目のケース「懷」では、Unicode 文字は 2 つしかありませんが、Java/Scala は 3 つの文字を含む文字列と見なしているようです。

では、ここで何が起こっているのでしょうか。また、私が言及したサイトのコンバーターと同じように、2 番目のケースを正しく変換するにはどうすればよいでしょうか? どうもありがとう。

アップデート:

  • 私のソース コード ファイルは UTF-8 を使用しています。
  • これが "懷".toCharArray() の結果です
    • char[] = ?, char.toInt = 55390
    • char[] = ?, char.toInt = 56743
    • char[] = 懷, char.toInt = 25079

今、私は何が起こったのか知っていると思います。文字 "" は UTF-16 で 0xD85E 0xDDA7 としてエンコードされ、2 バイトではなく 4 バイトになります。charそのため、データ型が 2 バイトしか表現できないchar の配列に変換すると、2 つの要素が必要になります。

4

3 に答える 3

7

Java (したがって Scala) は文字列に UTF-16 エンコーディングを使用します。つまり、2^16-1 を超えるすべての Unicode コード ポイントは 2 文字で表す必要があります。(実際には、エンコーディング スキームはそれよりも少し複雑です。) とにかく、lengthは下位レベル (文字) で動作するメソッドであるため、文字数を返します。

コード ポイントの数を知りたい場合は、「2 つの Unicode 文字」(たとえば、出力される 2 つの記号) と言うときにおそらく直感的に考えられるものですs.codePointCount(0,s.length)Charまた、それらを 16 進数に変換する場合は、すべてのコード ポイントが適合するわけではないため、s ではなくコード ポイントを使用する必要があります。この質問に対する私の回答には、文字列をコード ポイントに変換する Scala コードが含まれています。(最大の効率ではありません。大きな文字列に対して負荷の高いテキスト処理を行っている場合は、arrays/ArrayBuffer を使用するように書き直してください。)

于 2011-03-07T10:39:41.650 に答える
2

それは、ユニコードで「サロゲート」と呼ばれるものです。例えば、

"懷" foreach { c =>
  println(java.lang.Character.UnicodeBlock.of(c))
}

版画

HIGH_SURROGATES
LOW_SURROGATES
CJK_UNIFIED_IDEOGRAPHS

ところで、私も台湾に拠点を置いています。Scala に興味があるなら、集まって話をしましょう。興味があれば、私のメールは私のプロフィールにあります。

于 2011-03-07T13:12:37.943 に答える
0

ファイルのエンコーディングを確認してください。IDE またはビルド スクリプトは、ファイルが UTF-8 または UTF-16 (どちらを使用しますか?) であることを認識している必要があります。BOMを定義する場合は、それが適切であることを確認してください。

于 2011-03-07T09:48:41.133 に答える