В каждом регионе мира есть свой местный язык. Региональные различия напрямую приводят к различиям в языковой среде. В процессе разработки международной программы важно решить языковые вопросы.
Эта проблема существует во всем мире, поэтому Java предлагает решение по всему миру. Метод, описанный в этой статье, предназначен для обработки китайского языка, но, в более широком смысле, он также применим и для обработки языков из других стран и регионов мира.
Китайские иероглифы двухбайтовые. Так называемый двойной байт означает, что двойное слово занимает две позиции БАЙТА (то есть 16 бит), которые называются старшими битами и младшими битами соответственно. В Китае указана обязательная кодировка китайских символов GB2312. В настоящее время почти все приложения, способные обрабатывать китайский язык, поддерживают GB2312. GB2312 включает китайские символы первого и второго уровня и 9 символов области. Старшие биты находятся в диапазоне от 0xa1 до 0xfe, а младшие биты также находятся в диапазоне от 0xa1 до 0xfe. Среди них диапазон кодирования китайских символов составляет от 0xb0a1 до 0xf7fe.
Есть еще одна кодировка GBK, но это спецификация, а не обязательная. GBK предоставляет 20902 китайских символа, что совместимо с GB2312, а диапазон кодировки составляет от 0x8140 до 0xfefe. Все символы GBK могут быть сопоставлены с Unicode 2.0 один за другим.
В ближайшем будущем Китай обнародует еще один стандарт: GB18030-2000 (GBK2K). В него вошли шрифты тибетских, монгольских и других этнических меньшинств, принципиально решающие проблему недостаточного положения символов. Примечание. Это больше не фиксированная длина. Двухбайтовая часть совместима с GBK, а четырехбайтовая часть представляет собой расширенные символы и глифы. Его первый и третий байты находятся в диапазоне от 0x81 до 0xfe, а второй и четвертый байты — от 0x30 до 0x39.
В этой статье не рассматривается Unicode. Желающие могут просмотреть http://www.unicode.org/ для просмотра дополнительной информации. У Unicode есть особенность: он включает в себя все глифы символов в мире. Таким образом, языки в различных регионах могут устанавливать отношения отображения с Unicode, и Java использует это для достижения преобразования между разнородными языками.
В JDK кодировки, относящиеся к китайскому языку:
Таблица 1. Список кодировок, относящихся к китайскому языку, в JDK.
Описание | имени кодировки |
ASCII | 7-битный, такой же, как ascii7 |
ISO8859-1 | 8-битный, такой же, как 8859_1, ISO-8859-1, ISO_8859-1, latin1... и т. д. |
GB2312-80 | 16-битный, такой же, как gb2312, gb2312 -1980, EUC_CN, euccn,1381,Cp1381, 1383, Cp1383, ISO2022CN,ISO2022CN_GB... и т. д. |
GBK | — то же самое, что и MS936. Примечание. UTF8 с учетом регистра |
— | то же самое, что и |
GB18030 | . то же самое, что cp1392 и 1392. В настоящее время |
на практике при программировании я больше всего сталкиваюсь с GB2312 (GBK) и ISO8859-1.
Почему стоит знак «?»
Как уже говорилось выше, преобразование между разными языками осуществляется посредством Unicode. Предположим, есть два разных языка A и B. Этапы преобразования таковы: сначала преобразовать A в Unicode, а затем преобразовать Unicode в B.
Приведите примеры. В GB2312 есть китайский иероглиф «李», его код — «C0EE», который необходимо преобразовать в код ISO8859-1. Шаги следующие: сначала преобразуйте символ «李» в Юникод, чтобы получить «674E», а затем преобразуйте «674E» в символы ISO8859-1. Конечно, такое сопоставление не удастся, поскольку в ISO8859-1 нет символа, соответствующего «674E».
Проблема возникает, когда сопоставление не удалось! Если при преобразовании с определенного языка в Юникод символ не существует в определенном языке, результатом будет код Юникод "uffffd" ("u" означает кодировку Юникод). При преобразовании из Unicode в определенный язык, если в определенном языке нет соответствующих символов, вы получите «0x3f» («?»). Вот откуда взялся знак "?".
Например: выполните операцию new String(buf, "gb2312") над потоком символов buf = "0x80 0x40 0xb0 0xa1", результатом будет "ufffdu554a", а затем распечатайте ее, результат будет " ?ah", потому что "0x80 0x40" — это символ в GBK, а не в GB2312.
В качестве другого примера выполните операцию new String (buf.getBytes("GBK")) над строкой String="u00d6u00ecu00e9u0046u00bbu00f9", и результатом будет "3fa8aca8a6463fa8b4", среди которых: "=6" В "GBK" соответствующего символа нет, поэтому получаем "3f", "u00ec" соответствует "a8ac", ">9" соответствует "a8a6", а "0046" соответствует "46" (потому что это символ ASCII), «u00bb» не найден, а «3f» получено. Наконец, «u00f9» соответствует «a8b4». Распечатайте эту строку и получите результат «?ìéF?ù». Вы это видели? Здесь не все знаки вопроса, поскольку содержимое, сопоставленное между GBK и Unicode, помимо китайских иероглифов включает в себя символы. Этот пример является лучшим доказательством.
Поэтому при перекодировании китайских иероглифов, если произойдет путаница, вы не обязательно получите вопросительные знаки! Однако ошибка есть ошибка. Качественной разницы между 50 шагами и 100 шагами нет.
Или вы можете спросить: каков будет результат, если он будет включен в исходный набор символов, но не в Unicode? Ответ: я не знаю. Потому что у меня нет под рукой исходного набора символов для проведения этого теста. Но одно можно сказать наверняка: исходный набор символов недостаточно стандартизирован. В Java, если это произойдет, будет выдано исключение.
Что такое UTF
UTF — это аббревиатура текстового формата Unicode, что означает текстовый формат Unicode. Для UTF он определяется следующим образом:
(1) Если первые 9 бит 16-битного символа Юникода равны 0, он представлен байтом. Первый бит этого байта равен «0», а остальные 7 битов. совпадают с исходным символом. Последние 7 цифр такие же, как «u0034» (0000 0000 0011 0100), представленные цифрой «34» (0011 0100) (то же, что и исходный символ Юникода)
; 2) Если первые 5 16-битных символов Юникода Если бит равен 0, он представлен 2 байтами. Первый байт начинается с «110», а следующие 5 битов совпадают со старшими 5 битами источника. символ после исключения первых 5 нулей; второй байт начинается с «10». Вначале следующие 6 бит такие же, как младшие 6 бит в исходном символе. Например, «=» (0000 0010 0101 1101) будет преобразовано в «c99d» (1100 1001 1001 1101)
(3) Если оно не соответствует двум вышеуказанным правилам, оно будет представлено тремя байтами. Первый байт начинается с «1110», а последние четыре бита — это старшие четыре бита исходного символа; второй байт начинается с «10», а последние шесть битов — это средние шесть битов исходного символа; байт начинается с «10». Начиная с «10», последние шесть цифр — это младшие шесть цифр исходного символа, например, «u9da7» (1001 1101 1010 0111) преобразуется в «e9b6a7» (1110 1001 1011); 0110 1010 0111);
разницу между Unicode и Unicode в JAVA-программах можно описать так. Связь между UTF не является абсолютной: при запуске строки в памяти она отображается как код Unicode, а при сохранении в файл. или другой носитель, используется UTF. Этот процесс преобразования завершается функциями writeUTF и readUTF.
Ладно, основное обсуждение почти закончено, давайте перейдем к делу.
Сначала подумайте о проблеме как о черном ящике. Давайте сначала посмотрим на представление черного ящика первого уровня:
input(charsetA)->process(Unicode)->output(charsetB)
— это просто. Это модель IPO, то есть ввод, обработка и вывод. Тот же контент необходимо преобразовать из charsetA в unicode, а затем в charsetB.
Давайте посмотрим на вторичное представление:
SourceFile(jsp,java)->class->output.
На этом рисунке видно, что входными данными являются исходные файлы jsp и java. Во время обработки файл класса используется в качестве носителя. а затем вывести. Затем уточните его до третьего уровня:
jsp->temp file->class->browser,os console,db
app,servlet->class->browser,os console,db
. Эта картина станет более ясной. Файл Jsp сначала создает промежуточный файл Java, а затем создает файл Class. Сервлеты и обычные приложения компилируются напрямую для создания класса. Затем выведите данные из класса в браузер, консоль или базу данных и т. д.
JSP: процесс перехода от исходного файла к классу.
Исходный файл Jsp представляет собой текстовый файл, заканчивающийся на «.jsp». В этом разделе будет объяснен процесс интерпретации и компиляции файлов JSP, а также будут отслеживаться изменения на китайском языке.
1. Инструмент преобразования JSP (jspc), предоставляемый механизмом JSP/Servlet, ищет кодировку, указанную в <%@ page contentType ="text/html; charset=<Jsp-charset>"%> в файле JSP. Если <Jsp-charset> не указан в файле JSP, используется настройка по умолчанию file.encoding в JVM. В обычных обстоятельствах это значение равно ISO8859-1;
2. jspc использует эквивалент «javac –encoding <Jsp». Команда -charset> " интерпретирует все символы, встречающиеся в файле JSP, включая китайские символы и символы ASCII, а затем преобразует эти символы в символы Юникода, затем преобразует их в формат UTF и сохраняет их как файлы JAVA. При преобразовании символов ASCII в символы Юникода вы просто добавляете впереди «00», например «A», который преобразуется в «u0041» (причина не требуется, именно так составляется таблица кодов Юникода). Затем, после преобразования в UTF, оно снова изменилось на «41»! Вот почему вы можете использовать обычный текстовый редактор для просмотра файлов JAVA, созданных JSP;
3. Механизм использует команду, эквивалентную «javac -encoding UNICODE», для компиляции файлов JAVA в файлы CLASS
; ситуация преобразования этих процессов. Существует следующий исходный код:
<%@ page contentType="text/html; charset=gb2312"%>
<html><body>
<%
String a="Китайский";
out.println(а);
%>
</body></html>
Этот код был написан в UltraEdit для Windows. После сохранения шестнадцатеричная кодировка двух символов «Китайский» будет «D6 D0 CE C4» (кодировка GB2312). После поиска в таблице кодировка слова «Китайский» в Юникоде — «u4E2Du6587», что в UTF — «E4 B8 AD E6 96 87». Откройте файл JAVA, преобразованный из файла JSP, созданного движком, и обнаружите, что слово «Китайский» действительно было заменено на «E4 B8 AD E6 96 87». Затем проверьте файл CLASS, созданный в результате компиляции файла JAVA, и найдите его. что результат такой же, как и в файле JAVA.
Давайте посмотрим на ситуацию, когда в JSP указан набор символов ISO-8859-1.
<%@ page contentType="text/html; charset=ISO-8859-1"%>
<html><body>
<%
String a="Китайский";
out.println(а);
%>
</body></html>
Аналогично, этот файл написан с помощью UltraEdit, и два символа «Китайский» также сохраняются как кодировка GB2312 «D6 D0 CE C4». Сначала смоделируйте процесс создания файлов JAVA и файлов CLASS: jspc использует ISO-8859-1 для интерпретации «китайского языка» и сопоставляет его с Unicode. Поскольку ISO-8859-1 является 8-битным и является латинским языком, его правило отображения заключается в добавлении «00» перед каждым байтом, поэтому сопоставленная кодировка Unicode должна быть «u00D6u00D0u00CEu00C4» после преобразования в UTF это должно быть «C3 96 C3 90 C3 8E C3 84». Хорошо, откройте файл и посмотрите. В файле JAVA и файле CLASS «китайский» действительно выражается как «C3 96 C3 90 C3 8E C3 84».
Если <Jsp-charset> не указан в приведенном выше коде, то есть первая строка записана как «<%@ page contentType="text/html" %>», JSPC будет использовать параметр file.encoding для интерпретации JSP-файл. В RedHat 6.2 результат обработки точно такой же, как при указании ISO-8859-1.
До сих пор был объяснен процесс сопоставления китайских иероглифов в процессе преобразования файлов JSP в файлы CLASS. Одним словом: от «JspCharSet до Unicode и UTF». В следующей таблице кратко описан этот процесс:
Таблица 2. «Китайский» процесс преобразования из JSP в CLASS.
Jsp-CharSet | В файле JSP В | файле JAVA | В файле CLASS |
GB2312 | D6 D0 CE C4 (GB2312) | от u4E2Du6587 (Unicode) до E4 B8 AD E6 96 87 (UTF) | E4 B8 AD E6 96 87 (UTF) |
ISO-8859 -1 | D6 D0 CE C4 (GB2312) | от u00D6u00D0u00CEu00C4 (Unicode) до C3 96 C3 90 C3 8E C3 84 (UTF) | C3 96 C3 90 C3 8E C3 84 (UTF) |
Нет (по умолчанию = file.encoding) | То же, что и ISO- 8859-1 | То же, что ISO-8859-1 | То же, что ISO-8859-1 |
Сервлет: процесс перехода от исходного файла к классу.
Исходный файл сервлета представляет собой текстовый файл, заканчивающийся на «.java». В этом разделе будет обсуждаться процесс компиляции сервлетов и отслеживать изменения на китайском языке.
Используйте «javac» для компиляции исходного файла сервлета. javac может принимать параметр «-encoding <Compile-charset>», что означает «использовать кодировку, указанную в <Compile-charset>, для интерпретации исходного файла Serlvet».
Когда исходный файл скомпилирован, используйте <Compile-charset> для интерпретации всех символов, включая китайские символы и символы ASCII. Затем преобразуйте символьные константы в символы Юникода и, наконец, преобразуйте Юникод в UTF.
В сервлете есть еще одно место для установки CharSet выходного потока. Обычно перед выводом результата вызывается метод setContentType HttpServletResponse для достижения того же эффекта, что и установка <Jsp-charset> в JSP, которая называется <Servlet-charset>.
Обратите внимание, что в статье упоминаются всего три переменные: <Jsp-charset>, <Compile-charset> и <Servlet-charset>. Среди них файлы JSP связаны только с <Jsp-charset>, а <Compile-charset> и <Servlet-charset> связаны только с сервлетом.
Посмотрите на следующий пример:
import javax.servlet.*;
import javax.servlet.http.*;
class testServlet расширяет HttpServlet.
{
public void doGet (HttpServletRequest req, HttpServletResponse соответственно)
выдает ServletException, java.io.IOException
{
resp.setContentType("text/html; charset=GB2312");
java.io.PrintWriter out=resp.getWriter();
out.println("<html>");
out.println("#中文#");
out.println("</html>");
}
}
Этот файл также написан с помощью UltraEdit для Windows, и два символа «Китайский» сохраняются как «D6 D0 CE C4» (кодировка GB2312).
Начните компилировать. В следующей таблице показан шестнадцатеричный код слова «Китайский» в файле CLASS, если <Compile-charset> отличается. Во время компиляции <Servlet-charset> не имеет никакого эффекта. <Servlet-charset> влияет только на вывод файла CLASS. Фактически, <Servlet-charset> и <Compile-charset> работают вместе для достижения того же эффекта, что и <Jsp-charset> в файле JSP, поскольку <Jsp-. charset >Это повлияет на компиляцию и вывод файлов CLASS.
Таблица 3. Процесс преобразования «Китайского языка» из исходного файла сервлета в класс
Набор символов компиляции. | Эквивалентный код Юникода | в файле классов | в исходном файле сервлета | :
GB2312 | D6 D0 CE C4. (GB2312) | E4 B8 AD E6 96 87 (UTF) | u4E2Du6587 (в Юникоде = «Китайский») |
ISO-8859-1 | D6 D0 CE C4 (GB2312) | C3 96 C3 90 C3 8E C3 84 (UTF) | u00D6 u00D0 u00CE u00C4 (перед D6 D0 CE C4 добавляется A 00) |
Нет (по умолчанию) | D6 D0 CE C4 (GB2312) | То же, что и ISO- 8859-1 | То же, что ISO-8859-1. |
№ | Шаг Описание | Результат |
1 | Запишите исходный файл JSP и сохраните его в формате GB2312 | D6 D0 CE C4 (D6D0=中文 CEC4=文) |
2 | jspc преобразует исходный файл JSP во временный файл JAVA, сопоставляет строку с Unicode в соответствии с GB2312 и записывает ее в файл JAVA в формате UTF | E4 B8 AD E6 96 87 |
3 | Скомпилируйте временный файл JAVA в файл CLASS | E4 B8 AD E6 96 87 |
4 | При запуске сначала прочитайте строку из файла CLASS с помощью readUTF. Кодировка Unicode в памяти — | 4E 2D 65 87 (в Unicode 4E2D=中文6587=文) |
5В соответствии | с | |
Jsp -charset=GB2312 Преобразовать Unicode в поток байтов | D6 D0 CE C4 | |
6 | Вывести поток байтов в IE и установить кодировку IE на GB2312 (примечание автора: эта информация скрыта в заголовке HTTP) | D6 D0 CE C4 |
7 | Просмотр в IE результаты «Китайский» с | «Упрощенным китайским» (правильное отображение) |
№ | Шаг Описание | Результат | |
1 | Запишите исходный файл JSP и сохраните его в формате GB2312 | D6 D0 CE C4 (D6D0=中文 CEC4=文) | |
2 | jspc преобразует исходный файл JSP во временный файл JAVA, сопоставляет строку с Unicode в соответствии с ISO8859-1 и записывает ее в файл JAVA в формате UTF | C3 96 C3 90 C3 8E C3 | |
84 | 3 | Временный файл JAVA компилируется в файл CLASS | C3 96 C3 90 C3 8E C3 84 |
4. | При запуске сначала прочитайте строку из файла CLASS с помощью readUTF. Кодировка Unicode в памяти: | 00 D6 00 D0 00 CE 00 C4. (Ничего!!!) | |
5 | Преобразовать Unicode в поток байтов | D6 D0 CE C4 | в соответствии с Jsp-charset=ISO8859-1|
6 | Вывести поток байтов в IE и установить кодировку IE на ISO8859-1 (авторская пресса: Эта информация скрыто в заголовке HTTP) | D6 D0 CE C4 | |
7 | IE использует «западноевропейские символы» для просмотра результата | в виде искаженных символов. На самом деле это четыре символа ASCII, но, поскольку оно больше 128, оно отображается странно. | |
8 | Измените кодировку страницы. из IE на «Упрощенный китайский» «中文» | «中文» (правильное отображение) |
№ | Шаг Описание | Результат | |
1 | Запишите исходный файл JSP и сохраните его в формате GB2312 | D6 D0 CE C4 (D6D0=中文 CEC4=文) | |
2 | jspc преобразует исходный файл JSP во временный файл JAVA, сопоставляет строку с Unicode в соответствии с ISO8859-1 и записывает ее в файл JAVA в формате UTF | C3 96 C3 90 C3 8E C3 | |
84 | 3 | Временный файл JAVA компилируется в файл CLASS | C3 96 C3 90 C3 8E C3 84 |
4. | При запуске сначала прочитайте строку из файла CLASS с помощью readUTF. Кодировка Unicode в памяти: | 00 D6 00 D0 00 CE 00 C4. | |
5. | Согласно Jsp-charset=ISO8859-1 Преобразование Unicode в поток байтов | D6 D0 CE C4 | |
6 | Вывод потока байтов в IE | D6 D0 CE C4 | |
7 | IE использует кодировку страницы при запросе для просмотра результатов, | в зависимости от ситуации. Если это упрощенный китайский, он может отображаться правильно. В противном случае необходимо выполнить шаг 8 в Таблице 5. |
№ | Шаг Описание | Результат |
1 | Запишите исходный файл сервлета и сохраните его в формате GB2312 | D6 D0 CE C4 (D6D0=китайский CEC4=китайский) |
2 | Используйте javac –encoding GB2312 для компиляции исходного файла JAVA в файл CLASS | E4 B8 AD E6 96 87 (UTF) |
3 | При запуске сначала прочитайте строку из файла CLASS с помощью readUTF и сохраните он находится в памяти. Кодировка — Unicode | 4E 2D 65 87 (Unicode) |
4 | Преобразовать Unicode в поток байтов | D6 D0 CE C4 (GB2312) | в соответствии с Servlet-charset=GB2312
5 | Вывести поток байтов в IE и установить атрибут кодирования IE на Servlet-charset=GB2312 | D6 D0 CE C4 (GB2312) |
6 | IE использует «упрощенный китайский» для просмотра результата | «китайский» (отображается правильно) |
№ | Шаг Описание | Результат |
1 | Запишите исходный файл сервлета и сохраните его в формате GB2312 | D6 D0 CE C4 (D6D0=中文 CEC4=文) |
2 | Используйте кодировку javac ISO8859-1 для компиляции исходного файла JAVA в файл CLASS | C3 96 C3 90 C3 8E C3 84 (UTF) |
3 | При запуске сначала прочитайте строку из файла CLASS, используя readUTF, кодировка Юникода в памяти — | 00 D6 00 D0 00 CE 00 C4 |
4 | Преобразовать Юникод в поток байтов в соответствии с Servlet-charset=ISO8859-1 | D6 D0 CE C4 |
5 | Вывести поток байтов в IE и установить кодировку IE Атрибут: Servlet-charset=ISO8859-1 | D6 D0 CE C4 (GB2312) |
6 | IE использует «западноевропейские символы» для просмотра | искаженных результатов (причина та же, что и в Таблице 5) |
7 | Измените кодировку страницы IE на «Упрощенный китайский» « | Китайский» (правильно отображается) |
Серийный номер | описание шага | Поле | результата |
1 | Введите «Китайский» в IE | D6 D0 CE C4 | IE |
2 | IE преобразует строку в UTF и отправляет ее в транспортный поток | E4 B8 AD E6 96 87 | |
3 | Сервлет получает входной поток и считывает его с помощью readUTF | 4E 2D 65 87 (unicode) | Сервлет |
4. | В сервлете программист должен восстановить строку в поток байтов | D6 D0 CE C4 | в соответствии с GB2312.|
5 | Программист генерирует новую строку | 00 D6 00 D0 00 CE | в соответствии с внутренним кодом базы данных ISO8859. -100 C4 |
6 | Отправьте вновь созданную строку в JDBC | 00 D6 00 D0 00 CE 00 C4 | |
7 | JDBC обнаруживает, что внутренний код базы данных — ISO8859-1 | 00 D6 00 D0 00 CE 00 C4 | JDBC |
8 | JDBC преобразует полученную строку. в соответствии с ISO8859 -1 Создать поток байтов | D6 D0 CE C4 | |
9 | JDBC записывает поток байтов в базу данных | D6 D0 CE C4 | |
10 | Завершить работу по хранению данных | D6 D0 CE C4 База данных | |
Ниже приведен процесс извлечения чисел из базы данных | |||
11 | JDBC извлекает слова из базы данных Throttle | D6 D0 CE C4 | JDBC |
12 | JDBC генерирует строку в соответствии с набором символов базы данных ISO8859-1 и отправляет ее сервлету | 00 D6 00 D0 00 CE 00 C4 (Unicode) | |
13 | Сервлет получает строку | 00 D6 00 D0 00 CE 00 C4 (Unicode) | Сервлет |
14 | Программист должен восстановить исходный поток байтов | D6 D0 CE C4 | в соответствии с внутренним кодом базы данных ISO8859-1.|
15 | Программисты должны генерировать новые строки в соответствии с набором символов клиента GB2312 | 4E 2D 65 87 (Юникод) | |
Сервлет готовится вывести строку клиенту | |||
16. | Сервлет генерирует поток байтов | D6D0 CE C4 | Servlet |
17 | на основе <Servlet-charset>. Сервлет выводит поток байтов в IE. Если указан <Servlet-charset>. Также будет установлен поток байтов IE. Кодировка: <Servlet-charset> | D6 D0 CE C4 | |
18 | IE. Просмотрите результат«Китайский» (правильно отображается) | в соответствии с указанной кодировкой или кодировкой по умолчанию | IE. |