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

Eu tentei usar o UTF-8 e tive problemas.

Eu tentei tantas coisas; aqui estão os resultados que obtive:

  • ???? em vez de caracteres asiáticos. Mesmo para o texto europeu, eu tenho Señor Se?or para o Señor .
  • Estranhos jargões (Mojibake?) Como Señor ou 新浪新闻 para 新浪新闻 .
  • Diamantes negros, como Se or.
  • Finalmente, entrei numa situação em que os dados foram perdidos, ou pelo menos truncados: Se for Señor .
  • Mesmo quando recebi o texto para parecer correto, ele não ordenou corretamente.

O que estou fazendo de errado? Como posso consertar o código ? Posso recuperar os dados ? Se sim, como?

Este problema afeta os participantes deste site e muitos outros.

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

Melhor pratica

A partir de agora, é 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 do utf8 , pois trata dos códigos utf8 de 4 bytes, que são necessários para o Emoji e para alguns dos chineses.

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

Vou tentar usar essas grafias e capitalizações para distinguir dentro e fora do MySQL a seguir.

Visão geral do que você deve fazer

  • Tenha seu editor, etc. definido como UTF-8.
  • Os formulários HTML devem começar como

    .

  • Tenha seus bytes codificados como UTF-8.
  • Estabeleça o UTF-8 como a codificação usada no cliente.
  • Ter a coluna / tabela declarada CHARACTER SET utf8mb4 (Marque com SHOW CREATE TABLE .)
  • no início do HTML

UTF-8 por todo o caminho

Mais detalhes sobre linguagens de computador (e suas próximas seções)

Teste os dados

Visualizar os dados com uma ferramenta ou com SELECT não pode ser confiável. Muitos desses clientes, especialmente os navegadores, tentam compensar as codificações incorretas e mostram o texto correto mesmo se o database for desconfigurado. Então, escolha uma tabela e coluna que tenha algum texto que não seja em 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
  • Para a maioria da Europa Ocidental, letras acentuadas devem ser Cxyy
  • Cirílico, hebraico e farsi / árabe: Dxyy
  • A maioria da Ásia: Exyyzz
  • Emoji e alguns dos chineses: F0yyzzww
  • Mais detalhes

Causas e reparações específicas dos problemas observados

Texto truncado ( Se para o Señor ):

  • Os bytes a serem armazenados não são codificados como utf8mb4. Conserte isso.
  • Além disso, verifique se a conexão durante a leitura é UTF-8.

Diamantes negros com pontos de interrogação ( Se or for Señor ); um desses casos existe:

Caso 1 (bytes originais não eram UTF-8):

  • Os bytes a serem armazenados não são codificados como utf8. Conserte isso.
  • A conexão (ou SET NAMES ) para o INSERT e o SELECT não foi utf8 / utf8mb4. Conserte isso.
  • Além disso, verifique se a coluna no database é CHARACTER SET utf8 (ou utf8mb4).

Caso 2 (os bytes originais eram UTF-8):

  • A conexão (ou SET NAMES ) para o SELECT não foi utf8 / utf8mb4. Conserte isso.
  • Além disso, verifique se a coluna no database é CHARACTER SET utf8 (ou utf8mb4).

Os diamantes negros ocorrem apenas quando o navegador está definido como .

Pontos de interrogação (regulares, não negros) ( Se?or para Señor ):

  • Os bytes a serem armazenados não são codificados como utf8 / utf8mb4. Conserte isso.
  • A coluna no database não é CHARACTER SET utf8 (ou utf8mb4). Conserte isso. (Use SHOW CREATE TABLE .)
  • Além disso, verifique se a conexão durante a leitura é UTF-8.

Mojibake ( Señor Señor ): (Esta discussão também se aplica a Double Encoding , que não é necessariamente visível.)

  • Os bytes a serem armazenados precisam ser codificados em UTF-8. Conserte isso.
  • A conexão quando INSERTing e SELECTing text precisa especificar utf8 ou utf8mb4. Conserte isso.
  • A coluna precisa ser declarada CHARACTER SET utf8 (ou utf8mb4). Conserte isso.
  • O HTML deve começar com .

Se os dados parecerem corretos, mas não forem classificados corretamente, você terá escolhido o agrupamento errado ou não haverá agrupamento adequado à sua necessidade ou haverá duplicação de codificação .

A codificação dupla pode ser confirmada 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 hex é aproximadamente o dobro do tempo que deveria ser. Isso é causado pela conversão de latin1 (ou qualquer outro) para utf8, tratando esses bytes como se fossem latin1 e repetindo a conversão. A sorting (e comparação) não funciona corretamente porque é, por exemplo, ordenada como se a cadeia fosse Señor .

Corrigindo os dados, quando possível

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

Para Mojibake / Double Encoding , …

Para Black Diamonds , …

(Eu vou ter que continuar isso em outra pergunta / resposta.)

Engraçado como você responde a sua própria pergunta 🙂

  1. Defina seu código de idioma IDE para UTF8

  2. Adicione ao header da sua página web onde você coleta o formulário de dados.

  3. Verifique se sua definição de tabela do MySQL é semelhante a esta:

     CREATE TABLE your_table ( ... ) ENGINE=InnoDB DEFAULT CHARSET=utf8 
  4. Se você estiver usando o PDO, certifique-se

     $options = array(PDO::MYSQL_ATTR_INIT_COMMAND=>'SET NAMES utf8'); $dbL = new PDO($pdo, $user, $pass, $options); 

Se você já tem um grande database com o problema acima, você pode tentar o SIDU para exportar com charset correto e importar de volta com o UTF8. Boa sorte

Dependendo de como o servidor está configurado, você precisa alterar a codificação de acordo. utf8 do que você disse deve funcionar melhor, no entanto, se você está recebendo caracteres estranhos pode ajudar se você mudar a página da Web Encode para Ansi. Isso me ajudou quando eu estava configurando um PHP MYSQLI isso pode ajudá-lo a entender mais https://superuser.com/questions/762473/ansi-to-utf-8-in-notepad