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 comSHOW 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
, ou7x
- 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 oINSERT
e oSELECT
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 oSELECT
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. (UseSHOW 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
eSELECTing
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