Java String-> unicode-> String преобразование несогласованности - PullRequest
3 голосов
/ 25 июня 2011

Я пытаюсь сериализовать строку Java в массив байтов, а затем снова десериализовать массив в строку. Казалось, он работал нормально, пока я не проверил юникодный символ \ude4e. По какой-то причине исходная строка "\ud34e" не равна десериализованной строке.

Это код сериализации (где encoding = Charset.forName( "UTF-16BE" ) и str = "\ud34e")

ByteArrayOutputStream out = new ByteArrayOutputStream();

Writer temp = new OutputStreamWriter( out, encoding );

temp.write( str );

temp.close();

byte[] bytes = out.toByteArray();

String deserialized = new String( bytes, encoding );

Так что я делаю не так? Спасибо!

Ответы [ 4 ]

6 голосов
/ 25 июня 2011

DE4E - это 1/2 суррогатной пары.Само по себе это недействительно.Это будет преобразовано в?или отбрасывается OutputStreamWriter.Если вы используете классы java.nio, вы можете увидеть ошибки.

3 голосов
/ 25 июня 2011

Когда я ищу код de4e в онлайн Unicode-диаграммах , он говорит, что этот код находится в Low Surrogate Charts. Это не символ сам по себе, а специальный код, который используется в UTF-16 (согласно документации там).

Юникод не так прост, как одиночный символ, сопоставленный с одной кодовой точкой - есть много причуд и вещей, и разные кодовые точки и последовательности байтов могут ссылаться на один и тот же символ.

Вполне возможно, что некоторые кодовые точки при сериализации и десериализации приводят к другой, но эквивалентной кодовой точке.

1 голос
/ 25 июня 2011
public static void main(String[] args) throws IOException {
    Charset encoding = Charset.forName( "UTF-16BE" );

    ByteArrayOutputStream out = new ByteArrayOutputStream();

    Writer temp = new OutputStreamWriter( out, encoding );

    String str = "\ud34e";

    temp.write( str );

    temp.close();

    byte[] bytes = out.toByteArray();

    String deserialized = new String( bytes, encoding );

    System.out.println("'" + str + "' / '" + deserialized + "' / " + (str.equals(deserialized)));
}

для меня вывод:

'?' / '?' / true

т.е. они равны ...

Я использую: Java-версия "1.6.0_24" Java (TM) Среда выполнения SE (сборка 1.6.0_24-b07) Java HotSpot (TM) Виртуальная 64-разрядная серверная виртуальная машина (сборка 19.1-b02, смешанный режим)

0 голосов
/ 26 июня 2011

Хотя это недопустимый символ, @Ant показывает, что кодирование-декодирование возвращает оригинал.Вероятно, это связано с тем, что UTF-16 является очень простым и прямым кодированием, совпадающим с 16-битным представлением символов Java.

Если мы поэкспериментируем с UTF-8, кодирование должно привести к фатальной ошибке.UTF-8 не может кодировать половину суррогатной пары.

...