Преобразование символа Unicode (CJK ExtB) в десятичные NCR в Java / Scala - PullRequest
1 голос
/ 07 марта 2011

Я пытаюсь преобразовать строку Java, содержащую символ Unicode в плане CJK ExtB, в десятичные 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?

Как видите, в первом случае он корректно преобразует три символа Юникод в три NCR.

Но во втором случае «? 懷» есть только два символа Юникода, но Java / Scala, похоже, считает, что это строка, содержащая три символа.

Итак, что здесь происходити как я могу преобразовать второй случай правильно, как конвертер на сайте, который я упомянул?Большое спасибо.

Обновление:

  • Мой файл исходного кода использует UTF-8.
  • Вот результат "? 懷" .toCharArray ()
    • char[] = ?, char.toInt = 55390
    • char[] = ?, char.toInt = 56743
    • char[] = 懷, char.toInt = 25079

Теперь я думаю, что знаю, что произошло.Символ «?» кодируется как 0xD85E 0xDDA7 в UTF-16, что составляет 4 байта вместо 2 байтов.Таким образом, при преобразовании в массив char требуется 2 элемента, где тип данных char может представлять только 2 байта.

Ответы [ 3 ]

7 голосов
/ 07 марта 2011

Java (и, следовательно, Scala) используют кодировку UTF-16 для своей строки, что означает, что все кодовые точки Unicode выше 2 ^ 16-1 должны быть представлены двумя символами. (На самом деле, схема кодирования на немного сложнее, чем .) В любом случае, length - это метод, который работает на более низком уровне - символах - поэтому он возвращает количество символов.

Если вы хотите узнать количество кодовых точек, о чем вы, вероятно, думаете интуитивно, когда говорите «два символа юникода» (например, два печатаемых символа), вам нужно использовать s.codePointCount(0,s.length). И если вы хотите преобразовать их в шестнадцатеричные, вам нужно работать с кодовыми точками, а не с Char s, так как не все кодовые точки подходят. Мой ответ на этот вопрос содержит код Scala для преобразования строки в кодовые точки. (Не с максимальной эффективностью; вы захотите переписать его для использования массивов / ArrayBuffer, если вы выполняете сложную обработку текста на больших строках.)

2 голосов
/ 07 марта 2011

Это то, что они называют "суррогатным" в Unicode говорят.Например,

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

печатает

HIGH_SURROGATES
LOW_SURROGATES
CJK_UNIFIED_IDEOGRAPHS

Кстати, я тоже на Тайване.Если вы заинтересованы в Scala, мы должны собраться и поговорить в магазине.Мой адрес электронной почты в моем профиле, если вы заинтересованы.

0 голосов
/ 07 марта 2011

Проверьте кодировку файла.Ваша IDE или ваш скрипт сборки должны знать, что это файл UTF-8 или UTF-16 (какой вы используете?).Если вы определите BOM , убедитесь, что оно подходит.

...