Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Problemas com caracteres UTF-8; o que vejo não é o que armazenei


Este problema atormenta os participantes deste site, e muitos outros.

Você listou os cinco principais casos de CHARACTER SET problemas.

Prática recomendada

No futuro, é melhor usar CHARACTER SET utf8mb4 e COLLATION utf8mb4_unicode_520_ci . (Há uma versão mais recente do agrupamento Unicode no pipeline.)

utf8mb4 é um superconjunto de utf8 na medida em que lida com códigos utf8 de 4 bytes, que são necessários para Emoji e alguns chineses.

Fora do MySQL, "UTF-8" refere-se a todas as codificações de tamanho, portanto, efetivamente o mesmo que utf8mb4 do MySQL , não utf8 .

Vou tentar usar essas grafias e letras maiúsculas para distinguir dentro e fora do MySQL a seguir.

Visão geral do que você deve fazer
  • Defina seu editor etc. como UTF-8.
  • Os formulários HTML devem começar como <form accept-charset="UTF-8"> .
  • Codifique seus bytes como UTF-8.
  • Estabeleça UTF-8 como a codificação que está sendo usada no cliente.
  • Declarar a coluna/tabela CHARACTER SET utf8mb4 (Verifique com SHOW CREATE TABLE .)
  • <meta charset=UTF-8> no início do HTML
  • As rotinas armazenadas adquirem o conjunto de caracteres/agrupamento atual. Eles podem precisar de reconstrução.

UTF- 8 até o fim

Mais detalhes para linguagens de computador (e suas seções seguintes)

Teste os dados

Visualizando os dados com uma ferramenta ou com SELECT não é confiável. Muitos desses clientes, especialmente navegadores, tentam compensar codificações incorretas e mostram o texto correto mesmo se o banco de dados estiver danificado. Então, escolha uma tabela e coluna que tenha algum texto diferente do inglês e faça
SELECT col, HEX(col) FROM tbl WHERE ...

O HEX para UTF-8 armazenado corretamente será
  • Para um espaço em branco (em qualquer idioma):20
  • Para inglês:4x , 5x , 6x , ou 7x
  • Na maior parte da Europa Ocidental, as letras acentuadas devem ser Cxyy
  • Cirílico, hebraico e farsi/árabe:Dxyy
  • A maior parte da Ásia:Exyyzz
  • Emoji e alguns de chinês:F0yyzzww
  • Mais detalhes

Causas específicas e correções dos problemas vistos

Truncado texto (Se para Señor ):
  • Os bytes a serem armazenados não são codificados como utf8mb4. Corrija isso.
  • Além disso, verifique se a conexão durante a leitura é UTF-8.

Diamantes Negros com pontos de interrogação (Se�or para Señor ); existe um destes casos:

Caso 1 (os bytes originais não UTF-8):
  • Os bytes a serem armazenados não são codificados como utf8. Corrija isso.
  • A conexão (ou SET NAMES ) para o INSERT e o SELECT não era utf8/utf8mb4. Corrija isso.
  • Verifique também se a coluna no banco de dados é CHARACTER SET utf8 (ou utf8mb4).

Caso 2 (bytes originais eram UTF-8):
  • A conexão (ou SET NAMES ) para o SELECT não era utf8/utf8mb4. Corrija isso.
  • Verifique também se a coluna no banco de dados é CHARACTER SET utf8 (ou utf8mb4).

Diamantes pretos ocorrem apenas quando o navegador está definido como <meta charset=UTF-8> .

Pontos de interrogação (normais, não diamantes negros) (Se?or para Señor ):
  • Os bytes a serem armazenados não são codificados como utf8/utf8mb4. Corrija isso.
  • A coluna no banco de dados não é CHARACTER SET utf8 (ou utf8mb4). Conserte isto. (Use SHOW CREATE TABLE .)
  • Além disso, verifique se a conexão durante a leitura é UTF-8.

Mojibake (Señor para Señor ):(Esta discussão também se aplica a Codificação Dupla , que não é necessariamente visível.)
  • Os bytes a serem armazenados precisam ser codificados em UTF-8. Corrija isso.
  • A conexão ao INSERT e SELECTing text precisa especificar utf8 ou utf8mb4. Corrija isso.
  • A coluna precisa ser declarada CHARACTER SET utf8 (ou utf8mb4). Corrija isso.
  • HTML deve começar com <meta charset=UTF-8> .

Se os dados parecerem corretos, mas não forem classificados corretamente, você escolheu o agrupamento errado ou não há agrupamento adequado à sua necessidade ou você tem Codificação dupla .

Codificação dupla pode ser confirmado fazendo o SELECT .. HEX .. descrito acima.
é should come back C3A9, but instead shows C383C2A9
The Emoji 👽 should come back F09F91BD, but comes back C3B0C5B8E28098C2BD

Ou seja, o hexadecimal é cerca de duas vezes maior do que deveria ser. Isso é causado pela conversão de latin1 (ou qualquer outra coisa) para utf8, depois tratando esses bytes como se fossem latin1 e repetindo a conversão. A classificação (e comparação) não funciona corretamente porque está, por exemplo, ordenando como se a string fosse Señor .

Corrigir os dados, sempre que possível

Para truncamento e pontos de interrogação , os dados são perdidos.

Para Mojibake / Codificação dupla , ...

Para Diamantes Negros , ...

As Correções estão listados aqui. (5 correções diferentes para 5 situações diferentes; escolha com cuidado):http://mysql. rjweb.org/doc.php/charcoll#fixes_for_various_cases