UTF-8 декодирование в Java - PullRequest
       32

UTF-8 декодирование в Java

7 голосов
/ 29 октября 2009

Я пытаюсь передать параметры из среднего уровня PHP в бэкэнд Java, который понимает J2EE. Я пишу код контроллера в Groovy. Там я пытаюсь декодировать некоторый параметр, который, вероятно, будет содержать международные символы.

Я до сих пор озадачен результатами отладки этой проблемы, поэтому я хотел поделиться ею с вами в надежде, что кто-то сможет дать правильную интерпретацию моих результатов.

Ради моего маленького теста, параметр, который я передаю, это "déjeuner". Просто чтобы быть уверенным, System.out.println ("déjeuner") правильно дает мне:

déjeuner

в консоли

Теперь ниже приведены значения char / dec и hex каждого символа оригинальной строки:

next char: d 100 64
next char: ? -61 c3
next char: ? -87 a9
next char: j 106 6a
next char: e 101 65
next char: u 117 75
next char: n 110 6e
next char: e 101 65
next char: r 114 72

обратите внимание, что последовательность c3a9 в UTF-8 является желаемым символом: http://www.fileformat.info/info/unicode/char/00e9/index.htm

Теперь, если я попытаюсь прочитать эту строку как строку UTF-8, как в stmt.getBytes ("UTF-8"), я внезапно получу последовательность из 11 байтов, как показано ниже:

64 c3 83 c2 a9 6a 65 75 6e 65 72

, тогда как stmt.getBytes ("iso-8859-1") дает мне 9 байтов:

64 c3 a9 6a 65 75 6e 65 72

обратите внимание на последовательность c3a9 здесь!

теперь, если я попытаюсь преобразовать последовательность UTF-8 в UTF-8, как в

new String(stmt.getBytes("UTF-8"), "UTF-8");

Я получаю:

next char: d 100 64
next char: ? -61 c3
next char: ? -87 a9
next char: j 106 6a
next char: e 101 65
next char: u 117 75
next char: n 110 6e
next char: e 101 65
next char: r 114 72

обратите внимание на последовательность c3a9

, а

new String(stmt.getBytes("iso-8859-1"), "UTF-8")

Результат:

next char: d 100 64
next char: ? -23 e9
next char: j 106 6a
next char: e 101 65
next char: u 117 75
next char: n 110 6e
next char: e 101 65
next char: r 114 72

обратите внимание на e9, который в utf-8 (и ascii), опять же, символ 'é', которого я так жажду.

К сожалению, ни в одном из случаев я не получаю правильную строку, которая будет отображаться как буквальная строка "déjeuner". Как ни странно, обе последовательности байтов кажутся правильными.

Ответы [ 4 ]

9 голосов
/ 29 октября 2009

При работе со строками всегда помните: byte! = char. Итак, в вашем первом примере у вас есть char c3, а не byte c3, что является огромной разницей: byte будет частью последовательности UTF-8, но char уже является Unicode . Поэтому, когда вы конвертируете это в UTF-8, символ Unicode c3 должен стать последовательностью byte c3 83.

Итак, вопрос в том, как вы получили String? В этом коде должна быть ошибка, которая неправильно обрабатывает кодированные в UTF-8 последовательности byte.

Причина, по которой ISO-8859-1 обычно работает, заключается в том, что эта кодировка не изменяет никакую char с кодовой точкой <256 (т. Е. Между 0 и 255), поэтому кодированные в UTF-8 последовательности <code>byte не будут быть изменены.

Ваш последний пример также неверен: char e9 находится в ISO-8859-1 и Unicode. В UTF-8 это недопустимо, так как это не byte и поскольку префикс byte c3 отсутствует. Тем не менее, он правильно представляет строку Unicode, которую вы ищете.

1 голос
/ 29 октября 2009

Если вы начинаете со строки Java, где "d\u00C3\u00A9jeuner".equals(stmt), то на этом этапе данные уже повреждены.

Java char не является C char. A char в Java имеет ширину 16 бит и неявно содержит кодированные данные UTF-16 . Попытка сохранить любые другие закодированные данные в типе Java char / String вызывает проблемы. Символьные данные в любой другой кодировке должны быть как byte data.

Если вы читаете параметр с помощью API сервлета , то, скорее всего, HTTP-запрос содержит противоречивую или недостаточную информацию о кодировке. Проверьте код вызова и заголовки HTTP. Вероятно, что клиент кодирует данные как UTF-8 , но сервлет декодирует их как ISO-8859-1 .

0 голосов
/ 16 февраля 2010

После некоторого дальнейшего исследования я нашел этот ответ

Как заставить UTF-8 работать в веб-приложениях Java? .

Это все о настройке URIEncoding = "UTF-8" в разъеме Tomcat.

Теперь выясним, как это сделать в CMS, которую мы используем (CQ5 / Day).

0 голосов
/ 16 февраля 2010

У меня очень похожая проблема, за исключением того, что моя форма использует запрос "GET", а не запрос "POST".

Итак, мой URL выглядит примерно так: http://localhost:4502/form.jsp?query=d%C3%A9jeuner

request.getCharacterEncoding() = ISO-8859-1
response.getCharacterEncoding() = UTF-8
request.getParameter("query") = déjeuner

Так что, должен ли HttpServletRequest использовать UTF-8 для декодирования параметра запроса (что явно не так) или это просто ошибка браузера, потому что браузер не устанавливает заголовок кодировки символов (что опять же не имеет большого смысла, потому что это не делать почтовый запрос). Вот полный набор заголовков и обратите внимание на% C3% A9 в URL.

http://localhost:4502/form.jsp?query=d%C3%A9juerne

GET /form.jsp?query=d%C3%A9juerne HTTP/1.1
Host: localhost:4502
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.17) Gecko/2010010604 Ubuntu/9.04 (jaunty) Firefox/3.0.17
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-gb,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive

Эта проблема у меня заключается в том, что я на самом деле скопировал и вставил запрос в форму браузера, и он неправильно закодировал его. Как в Chrome, так и в Firefox.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...