Cada região do mundo tem seu próprio idioma local. As diferenças regionais levam diretamente a diferenças no ambiente linguístico. No processo de desenvolvimento de um programa internacional, é importante lidar com questões linguísticas.
Este é um problema que existe em todo o mundo, então Java fornece uma solução mundial. O método descrito neste artigo é para processamento de chinês, mas, por extensão, também é aplicável ao processamento de idiomas de outros países e regiões do mundo.
Os caracteres chineses são de byte duplo. O chamado byte duplo significa que uma palavra dupla ocupa duas posições de BYTE (ou seja, 16 bits), que são chamadas de bits altos e bits baixos, respectivamente. A codificação de caracteres chineses especificada na China é GB2312, que é obrigatória. Atualmente, quase todos os aplicativos que podem processar chinês suportam GB2312. GB2312 inclui caracteres chineses de primeiro e segundo nível e 9 símbolos de área. Os bits altos variam de 0xa1 a 0xfe, e os bits baixos também variam de 0xa1 a 0xfe. Entre eles, a faixa de codificação de caracteres chineses é 0xb0a1 a 0xf7fe.
Existe outra codificação chamada GBK, mas esta é uma especificação, não obrigatória. GBK fornece 20.902 caracteres chineses, que são compatíveis com GB2312, e o intervalo de codificação é de 0x8140 a 0xfefe. Todos os caracteres em GBK podem ser mapeados para Unicode 2.0 um por um.
Num futuro próximo, a China promulgará outro padrão: GB18030-2000 (GBK2K). Inclui fontes de minorias tibetanas, mongóis e outras minorias étnicas, resolvendo fundamentalmente o problema de posições de caráter insuficientes. Observação: não tem mais comprimento fixo. A parte de dois bytes é compatível com GBK e a parte de quatro bytes contém caracteres estendidos e glifos. Seu primeiro e terceiro bytes variam de 0x81 a 0xfe, e seu segundo e quarto bytes variam de 0x30 a 0x39.
Este artigo não pretende apresentar o Unicode. Os interessados podem navegar em "http://www.unicode.org/" para obter mais informações. O Unicode tem uma característica: inclui todos os glifos de caracteres do mundo. Portanto, linguagens em diversas regiões podem estabelecer relacionamentos de mapeamento com Unicode, e Java aproveita isso para conseguir conversão entre linguagens heterogêneas.
No JDK, as codificações relacionadas ao chinês são:
Tabela 1 Lista de codificações relacionadas ao chinês no JDK
Nome da codificação | descrição |
ASCII | 7 bits, igual a ascii7 |
ISO8859-1 | 8 bits, igual a 8859_1, ISO-8859-1, ISO_8859-1, latin1... etc. |
GB2312-80 | 16 bits, igual a gb2312, gb2312 |
Cp1381 | , |
1383 | , |
Cp1383, ISO2022CN,ISO2022CN_GB...etc são | |
iguais | . |
o mesmo que cp1392 e 1392. Atualmente, poucos JDKs são suportados |
na prática na programação, os que tenho mais contato são GB2312 (GBK) e ISO8859-1.
Por que existe um sinal “?”
Como mencionado acima, a conversão entre diferentes idiomas é realizada por meio de Unicode. Suponha que existam dois idiomas diferentes, A e B. As etapas de conversão são: primeiro converter A em Unicode e, em seguida, converter Unicode em B.
Dê exemplos. Existe um caractere chinês "李" no GB2312 e seu código é "C0EE", que precisa ser convertido para o código ISO8859-1. As etapas são: primeiro converta o caractere "李" em Unicode para obter "674E" e, em seguida, converta "674E" em caracteres ISO8859-1. É claro que esse mapeamento não será bem-sucedido, pois não há nenhum caractere correspondente a “674E” na ISO8859-1.
O problema ocorre quando o mapeamento não é bem-sucedido! Ao converter de um determinado idioma para Unicode, se o caractere não existir em um determinado idioma, o resultado será o código Unicode "uffffd" ("u" significa codificação Unicode). Ao converter de Unicode para um determinado idioma, se um determinado idioma não tiver caracteres correspondentes, você obterá "0x3f" ("?"). É daí que vem o "?"
Por exemplo: execute a nova operação String(buf, "gb2312") no fluxo de caracteres buf = "0x80 0x40 0xb0 0xa1", o resultado será "ufffdu554a" e, em seguida, imprima-o, o resultado será " ?ah", porque "0x80 0x40" é um caractere em GBK, não em GB2312.
Para outro exemplo, execute a nova operação String (buf.getBytes("GBK")) na string String="u00d6u00ecu00e9u0046u00bu00f9", e o resultado é "3fa8aca8a6463fa8b4", entre os quais, "u00d6 "Não há caractere correspondente em "GBK", então obtemos "3f", "u00ec" corresponde a "a8ac", "u00e9" corresponde a "a8a6" e "0046" corresponde a "46" (porque este é um caractere ASCII), "u00b" não foi encontrado e "3f" foi obtido. Finalmente, "u00f9" corresponde a "a8b4". Imprima esta string e o resultado será "?ìéF?ù". Você viu isso? Nem tudo são pontos de interrogação aqui, porque o conteúdo mapeado entre GBK e Unicode inclui caracteres além dos caracteres chineses. Este exemplo é a melhor prova.
Portanto, ao transcodificar caracteres chineses, se ocorrer confusão, você não receberá necessariamente pontos de interrogação! No entanto, afinal, um erro é um erro. Não há diferença qualitativa entre 50 passos e 100 passos.
Ou você pode perguntar: Qual será o resultado se for incluído no conjunto de caracteres de origem, mas não no Unicode? A resposta é não sei. Porque não tenho o conjunto de caracteres de origem em mãos para fazer este teste. Mas uma coisa é certa: o conjunto de caracteres de origem não é padronizado o suficiente. Em Java, se isso acontecer, uma exceção será lançada.
O que é UTF
UTF é a abreviatura de Unicode Text Format, que significa formato de texto Unicode. Para UTF, é definido da seguinte forma:
(1) Se os primeiros 9 bits de um caractere Unicode de 16 bits forem 0, ele será representado por um byte. O primeiro bit deste byte é "0" e os 7 bits restantes.
são iguais aocaractere
original. Os últimos 7 dígitos são iguais, como "u0034" (0000 0000 0011 0100), representado por "34" (0011 0100);
2) Se os primeiros 5 caracteres de 16 bits do Unicode Se o bit for 0, ele será representado por 2 bytes. O primeiro byte começa com "110" e os 5 bits seguintes são iguais aos 5 bits mais altos da fonte. caractere após excluir os primeiros 5 zeros; o segundo byte começa com "10" No início, os próximos 6 bits são iguais aos 6 bits inferiores no caractere de origem. Por exemplo, "u025d" (0000 0010 0101 1101) será convertido em "c99d" (1100 1001 1001 1101)
(3) Se não atender às duas regras acima, será representado por três bytes; O primeiro byte começa com "1110" e os últimos quatro bits são os quatro bits superiores do caractere de origem; o segundo byte começa com "10" e os últimos seis bits são os seis bits intermediários do caractere de origem; byte começa com "10". Começando com "10", os últimos seis dígitos são os seis dígitos inferiores do caractere de origem, por exemplo, "u9da7" (1001 1101 1010 0111) é convertido em "e9b6a7" (1110 1001 1011); 0110 1010 0111);
a diferença entre Unicode e Unicode em programas JAVA pode ser descrita assim A relação entre UTF não é absoluta: quando uma string é executada na memória, ela aparece como um código Unicode, e quando é salva em um arquivo ou outra mídia, UTF é usado. Este processo de conversão é concluído por writeUTF e readUTF.
Ok, a discussão básica está quase terminada, vamos direto ao ponto.
Primeiro pense no problema como uma caixa preta. Vejamos primeiro a representação de primeiro nível da caixa preta:
input(charsetA)->process(Unicode)->output(charsetB)
é simples. Este é um modelo IPO, ou seja, entrada, processamento e saída. O mesmo conteúdo precisa ser convertido de charsetA para unicode e depois para charsetB.
Vejamos a representação secundária:
SourceFile(jsp,java)->class->output
Nesta figura, pode-se observar que a entrada são arquivos fonte jsp e java. Durante o processamento, o arquivo Class é usado como portador. e depois saída. Em seguida, refine-o para o terceiro nível:
jsp->temp file->class->browser,os console,db
app,servlet->class->browser,os console,db
. O arquivo Jsp primeiro gera o arquivo Java intermediário e depois gera a Classe. Servlets e aplicativos comuns são compilados diretamente para gerar classes. Em seguida, envie a saída da classe para o navegador, console ou banco de dados, etc.
JSP: O processo do arquivo fonte até a classe
O arquivo fonte do Jsp é um arquivo de texto que termina com ".jsp". Nesta seção, o processo de interpretação e compilação de arquivos JSP será explicado e as alterações chinesas serão rastreadas.
1. A ferramenta de conversão JSP (jspc) fornecida pelo mecanismo JSP/Servlet procura o conjunto de caracteres especificado em <%@ page contentType ="text/html; charset=<Jsp-charset>"%> no arquivo JSP. Se <Jsp-charset> não for especificado no arquivo JSP, a configuração padrão file.encoding na JVM será usada. Em circunstâncias normais, esse valor é ISO8859-1.
jspc usa o equivalente a "javac –encoding <Jsp; -charset> "o comando interpreta todos os caracteres que aparecem no arquivo JSP, incluindo caracteres chineses e caracteres ASCII, e então converte esses caracteres em caracteres Unicode, depois os converte para o formato UTF e os salva como arquivos JAVA. Ao converter caracteres ASCII em caracteres Unicode, basta adicionar "00" na frente, como "A", que é convertido em "u0041" (não é necessário motivo, é assim que a tabela de códigos Unicode é compilada). Então, após a conversão para UTF, voltou a ser "41"! É por isso que você pode usar um editor de texto comum para visualizar os arquivos JAVA gerados pelo JSP
3. O mecanismo usa o comandoequivalente
a "javac -encoding UNICODE" para compilar os arquivos JAVA em arquivos CLASS;
situação de conversão desses processos. Existe o seguinte código-fonte:
<%@ page contentType="text/html; charset=gb2312"%>
<html><corpo>
<%
String a="Chinês";
out.println(a);
%>
</body></html>
Este código foi escrito no UltraEdit para Windows. Depois de salvar, a codificação hexadecimal dos dois caracteres "chinês" é "D6 D0 CE C4" (codificação GB2312). Depois de consultar a tabela, a codificação Unicode da palavra "chinês" é "u4E2Du6587", que em UTF é "E4 B8 AD E6 96 87". Abra o arquivo JAVA convertido do arquivo JSP gerado pelo mecanismo e descubra que a palavra "Chinês" foi realmente substituída por "E4 B8 AD E6 96 87". Em seguida, verifique o arquivo CLASS gerado pela compilação do arquivo JAVA e encontre. que o resultado é o mesmo que Exatamente o mesmo que no arquivo JAVA.
Vejamos a situação em que o CharSet especificado em JSP é ISO-8859-1.
<%@ page contentType="text/html; charset=ISO-8859-1"%>
<html><corpo>
<%
String a="Chinês";
out.println(a);
%>
</body></html>
Da mesma forma, este arquivo é escrito com UltraEdit, e os dois caracteres "chinês" também são armazenados como codificação GB2312 "D6 D0 CE C4". Primeiro simule o processo de geração de arquivos JAVA e arquivos CLASS: jspc usa ISO-8859-1 para interpretar "chinês" e mapeia-o para Unicode. Como ISO-8859-1 é de 8 bits e é uma linguagem latina, sua regra de mapeamento é adicionar "00" antes de cada byte, portanto, a codificação Unicode mapeada deve ser "u00D6u00D0u00CEu00C4" , após a conversão para UTF deveria ser "C3 96 C3 90 C3 8E C3 84". Ok, abra o arquivo e dê uma olhada no arquivo JAVA e no arquivo CLASS, "Chinês" é realmente expresso como "C3 96 C3 90 C3 8E C3 84".
Se <Jsp-charset> não for especificado no código acima, ou seja, a primeira linha for escrita como "<%@ page contentType="text/html" %>", o JSPC usará a configuração file.encoding para interpretar o Arquivo JSP. No RedHat 6.2, o resultado do processamento é exatamente o mesmo da especificação ISO-8859-1.
Até agora, foi explicado o processo de mapeamento de caracteres chineses no processo de conversão de arquivos JSP para arquivos CLASS. Em uma palavra: De "JspCharSet para Unicode para UTF". A tabela a seguir resume esse processo:
Tabela 2 Processo de conversão "chinês" de JSP para CLASS
Jsp-CharSet | No arquivo JSP No | arquivo JAVA | No arquivo CLASS |
GB2312 | D6 D0 CE C4 (GB2312) | de u4E2Du6587 (Unicode) para E4 B8 AD E6 96 87 (UTF) | E4 B8 AD E6 96 87 (UTF) |
ISO-8859 -1 | D6 D0 CE C4 (GB2312) | de u00D6u00D0u00CEu00C4 (Unicode) para C3 96 C3 90 C3 8E C3 84 (UTF) | C3 96 C3 90 C3 8E C3 84 (UTF) |
Nenhum (padrão = file.encoding) | O mesmo que ISO- 8859 -1 | Igual a ISO-8859-1 | Igual a ISO-8859-1 |
Servlet: O processo do arquivo de origem até a classe.
O arquivo de origem do Servlet é um arquivo de texto que termina com ".java". Esta seção discutirá o processo de compilação do Servlet e acompanhará as alterações chinesas.
Use "javac" para compilar o arquivo fonte do Servlet. javac pode usar o parâmetro "-encoding <Compile-charset>", que significa "usar a codificação especificada em <Compile-charset> para interpretar o arquivo de origem do Serlvet".
Quando o arquivo de origem for compilado, use <Compile-charset> para interpretar todos os caracteres, incluindo caracteres chineses e caracteres ASCII. Em seguida, converta as constantes de caracteres em caracteres Unicode e, por fim, converta Unicode em UTF.
No Servlet, há outro local para definir o CharSet do fluxo de saída. Normalmente, antes de gerar o resultado, o método setContentType de HttpServletResponse é chamado para obter o mesmo efeito que a configuração <Jsp-charset> em JSP, que é chamada <Servlet-charset>.
Observe que um total de três variáveis são mencionadas no artigo: <Jsp-charset>, <Compile-charset> e <Servlet-charset>. Entre eles, os arquivos JSP estão relacionados apenas ao <Jsp-charset>, enquanto <Compile-charset> e <Servlet-charset> estão relacionados apenas ao Servlet.
Veja o exemplo a seguir:
import javax.servlet.*;
import
javax.servlet.http.*;
{
public void doGet(HttpServletRequest req,HttpServletResponse resp)
lança ServletException,java.io.IOException
{
resp.setContentType("text/html; charset=GB2312");
java.io.PrintWriter out=resp.getWriter();
out.println("<html>");
out.println("#中文#");
out.println("</html>");
}
}
Este arquivo também foi escrito com UltraEdit para Windows e os dois caracteres "chinês" são salvos como "D6 D0 CE C4" (codificação GB2312).
Comece a compilar. A tabela a seguir mostra o código hexadecimal da palavra "chinês" no arquivo CLASS quando <Compile-charset> é diferente. Durante a compilação, <Servlet-charset> não tem efeito. <Servlet-charset> afeta apenas a saída do arquivo CLASS. Na verdade, <Servlet-charset> e <Compile-charset> trabalham juntos para obter o mesmo efeito que <Jsp-charset> no arquivo JSP, porque <Jsp-. charset >Isso terá um impacto na compilação e saída de arquivos CLASS.
Tabela 3 O processo de transformação de "Chinês" do arquivo fonte do Servlet para Classe
Compile-charset | O código Unicode equivalente | no arquivo de classe | no arquivo de origem do Servlet | é
GB2312 | D6 D0 CE C4 (GB2312) | E4 B8 AD E6 96 87 (UTF) | u4E2Du6587 (em Unicode = "chinês") |
ISO-8859-1 | D6 D0 CE C4 (GB2312) | C3 96 C3 90 C3 8E C3 84 (UTF) | u00D6 u00D0 u00CE u00C4 (A 00 é adicionado na frente de D6 D0 CE C4) |
Nenhum (padrão) | D6 D0 CE C4 (GB2312) | Igual a ISO- 8859 -1 | Igual a ISO-8859-1 |
Nº | Etapa Descrição | Resultado |
1 | Escreva o arquivo de origem JSP e salve-o no formato GB2312 | D6 D0 CE C4 (D6D0=中文 CEC4=文) |
2 | jspc converte o arquivo de origem JSP em um arquivo JAVA temporário, mapeia a string para Unicode de acordo com GB2312 e a grava no arquivo JAVA no formato UTF | E4 B8 AD E6 96 87 |
3 | Compilar o arquivo temporário Arquivo JAVA em um arquivo CLASS | E4 B8 AD E6 96 87 |
4 | Ao executar, primeiro leia a string do arquivo CLASS usando readUTF. A codificação Unicode na memória é | 4E 2D 65 87 (em Unicode 4E2D=中文6587=文) |
5De acordo | com. Jsp -charset = GB2312 Converter Unicode em fluxo de bytes | D6 D0 CE C4 |
6 | Produza o fluxo de bytes para IE e defina a codificação do IE para GB2312 (Nota do autor: esta informação está oculta no cabeçalho HTTP) | D6 D0 CE C4 |
7 | IE View resultados "Chinês" com | "Chinês Simplificado" (exibição correta) |
Nº | Etapa Descrição | Resultado | |
1 | Escreva o arquivo de origem JSP e salve-o no formato GB2312 | D6 D0 CE C4 (D6D0=中文 CEC4=文) | |
2 | jspc converte o arquivo de origem JSP em um arquivo JAVA temporário, mapeia a string para Unicode de acordo com ISO8859-1 e grava-a no arquivo JAVA no formato UTF | C3 96 C3 90 C3 8E C3 | |
84 | 3 | O arquivo JAVA temporário é compilado em um arquivo CLASS | C3 96 C3 90 C3 8E C3 84 |
4. | Ao executar, primeiro leia a string do arquivo CLASS usando readUTF. A codificação Unicode na memória é | 00 D6 00 D0 00 CE 00 C4. (Nada!!!) | |
5 | Converta Unicode em fluxo de bytes | D6 D0 CE C4 | de acordo com Jsp-charset = ISO8859-1|
6 | Envie o fluxo de bytes para IE e defina a codificação do IE para ISO8859-1 (imprensa do autor: Esta informação é oculto no cabeçalho HTTP) | D6 D0 CE C4 | |
7 | IE usa "caracteres da Europa Ocidental" para visualizar o resultado | como caracteres ilegíveis. Na verdade, são quatro caracteres ASCII, mas como é maior que 128, é exibido de forma estranha. | |
8 | Altere a codificação da página. do IE para "Chinês Simplificado" "中文" | "中文" (exibição correta) |
Nº | Etapa Descrição | Resultado | |
1 | Escreva o arquivo de origem JSP e salve-o no formato GB2312 | D6 D0 CE C4 (D6D0=中文 CEC4=文) | |
2 | jspc converte o arquivo de origem JSP em um arquivo JAVA temporário, mapeia a string para Unicode de acordo com ISO8859-1 e grava-a no arquivo JAVA no formato UTF | C3 96 C3 90 C3 8E C3 | |
84 | 3 | O arquivo JAVA temporário é compilado em um arquivo CLASS | C3 96 C3 90 C3 8E C3 84 |
4. | Ao executar, primeiro leia a string do arquivo CLASS usando readUTF. A codificação Unicode na memória é | 00 D6 00 D0 00 CE 00 C4. | |
5. | De acordo com Jsp- charset = ISO8859-1 Converter Unicode em um fluxo de bytes | D6 D0 CE C4 | |
6 | Produza o fluxo de bytes para IE | D6 D0 CE C4 | |
7 | O IE usa a codificação da página quando a solicitação é feita para visualizar os resultados, | dependendo da situação. Se for chinês simplificado, pode ser exibido corretamente. Caso contrário, a etapa 8 da Tabela 5 precisa ser executada. |
Nº | Etapa Descrição | Resultado |
1 | Grave o arquivo de origem do Servlet e salve-o no formato GB2312 | D6 D0 CE C4 (D6D0=Chinês CEC4=Chinês) |
2 | Use javac –encoding GB2312 para compilar o arquivo de origem JAVA em um arquivo CLASS | E4 B8 AD E6 96 87 (UTF) |
3 | Ao executar, primeiro leia a string do arquivo CLASS usando readUTF e armazene na memória A codificação é Unicode | 4E 2D 65 87 (Unicode) |
4 | Converta Unicode em fluxo de bytes | D6 D0 CE C4 (GB2312) | de acordo com Servlet-charset = GB2312
5 | Envie o fluxo de bytes para IE e defina o atributo de codificação do IE para Servlet- charset=GB2312 | D6 D0 CE C4 (GB2312) |
6 | IE usa "Chinês Simplificado" para visualizar o resultado | "Chinês" (exibido corretamente) |
Nº | Etapa Descrição | Resultado |
1 | Grave o arquivo de origem do Servlet e salve-o no formato GB2312 | D6 D0 CE C4 (D6D0=中文 CEC4=文) |
2 | Use javac –encoding ISO8859-1 para compilar o arquivo de origem JAVA em um arquivo CLASS | C3 96 C3 90 C3 8E C3 84 (UTF) |
3 | Ao executar, primeiro leia a string do arquivo CLASS usando readUTF , a codificação Unicode na memória é | 00 D6 00 D0 00 CE 00 C4 |
4 | Converta Unicode em um fluxo de bytes de acordo com Servlet-charset = ISO8859-1 | D6 D0 CE C4 |
5 | Envie o fluxo de bytes para o IE e defina a codificação do IE O atributo é Servlet-charset=ISO8859-1 | D6 D0 CE C4 (GB2312) |
6 | O IE usa "caracteres da Europa Ocidental" para visualizar | resultados distorcidos (o motivo é o mesmo da Tabela 5) |
7 | Altere a codificação da página do IE para "Chinês Simplificado " | "Chinês" (exibido corretamente) |
Descrição da etapa do | número de série | Campo | de resultado |
1 | Digite "Chinês" no IE | D6 D0 CE C4 | IE |
2 | O IE converte a string em UTF e a envia para o fluxo de transporte | E4 B8 AD E6 96 87 | |
3 | O servlet recebe o fluxo de entrada e o lê com readUTF | 4E 2D 65 87 (unicode) | Servlet |
4 | No Servlet, o programador deve restaurar a string para um fluxo de bytes | D6 D0 CE C4 | de acordo com GB2312|
5 | O programador gera uma nova string | 00 D6 00 D0 00 CE | de acordo com o código interno do banco de dados ISO8859.-1.00 C4 |
6 | Envia a string recém-gerada para JDBC | 00 D6 00 D0 00 CE 00 C4 | |
7 | JDBC detecta que o código interno do banco de dados é ISO8859-1 | 00 D6 00 D0 00 CE 00 C4 | JDBC |
8 | JDBC converte a string recebida de acordo com ISO8859 -1 Gerar fluxo de bytes | D6 D0 CE C4 | |
9 | JDBC grava o fluxo de bytes no banco de dados | D6 D0 CE C4 | |
10 | Concluir o trabalho de armazenamento de dados | D6 D0 CE C4 Banco de dados | |
A seguir está o processo de recuperação de números do banco de dados | |||
11 | JDBC recupera palavras do banco de dados Throttle | D6 D0 CE C4 | JDBC |
12 | JDBC gera uma string de acordo com o conjunto de caracteres do banco de dados ISO8859-1 e a envia para o Servlet | 00 D6 00 D0 00 CE 00 C4 (Unicode) | |
13 | Servlet obtém a string | 00 D6 00 D0 00 CE 00 C4 (Unicode) | Servlet |
14 | O programador deve restaurar o fluxo de bytes original | D6 D0 CE C4 | de acordo com o código interno ISO8859-1 do banco de dados.|
15 | Os programadores devem gerar novas strings de acordo com o conjunto de caracteres do cliente GB2312 | 4E 2D 65 87 (Unicode) | |
O Servlet se prepara para enviar a string para o cliente | |||
16. | O Servlet gera o fluxo de bytes | D6D0 CE C4 | Servlet |
17 | com base em <Servlet-charset>. O Servlet gera o fluxo de bytes para o IE. O fluxo de bytes do IE também será definido. A codificação é <Servlet-charset> | D6 D0 CE C4 | |
18 | IE Visualize o resultado"Chinês" (exibido corretamente) | de acordo com a codificação especificada ou codificação padrão | do IE. |