UTF-8字符有问题; 我看到的不是我存储的东西

Ric*_*mes 66 mysql unicode utf-8 character-encoding mariadb

我试图使用UTF-8并遇到麻烦.

我尝试了很多东西; 这是我得到的结果:

  • ????而不是亚洲人物.即使是欧洲文本,我也得到Se?orSeñor.
  • 奇怪的胡言乱语(Mojibake?)如Señor新浪新闻????.
  • 黑色钻石,如Se or.
  • 最后,我陷入了数据丢失或至少被截断的情况:Sefor Señor.
  • 即使我看到正确的文字,它也没有正确排序.

我究竟做错了什么?我该如何修复代码?我可以恢复数据,如果是,如何恢复?

Ric*_*mes 106

这个问题困扰着这个网站的参与者和许多其他人.

你已经列出了五个主要的CHARACTER SET麻烦案例.

最佳实践

展望未来,最好使用CHARACTER SET utf8mb4COLLATION utf8mb4_unicode_520_ci.(管道中有一个较新版本的Unicode排序规则.)

utf8mb4它是一个超集,utf8因为它处理4字节的utf8代码,这是Emoji和一些中文所需要的.

在MySQL之外,"UTF-8"指的是所有大小的编码,因此实际上与MySQL相同utf8mb4,而不是utf8.

我将尝试使用这些拼写和大写来区分内部和外部MySQL.

该做什么的概述

  • 让您的编辑器等设置为UTF-8.
  • HTML表单应该像<form accept-charset="UTF-8">.
  • 将您的字节编码为UTF-8.
  • 将UTF-8建立为客户端中使用的编码.
  • 声明列/表CHARACTER SET utf8mb4(检查SHOW CREATE TABLE.)
  • <meta charset=UTF-8> 在HTML的开头

UTF-8一路走来

计算机语言的更多细节(及其以下部分)

测试数据

使用工具或使用工具查看数据SELECT无法信任.太多此类客户端(尤其是浏览器)会尝试补偿不正确的编码,并向您显示正确的文本,即使数据库被破坏也是如此.因此,选择一个包含非英文文本的表和列

SELECT col, HEX(col) FROM tbl WHERE ...
Run Code Online (Sandbox Code Playgroud)

正确存储的UTF-8的HEX将是

  • 对于空白区域(使用任何语言): 20
  • 对于英语: 4x,5x,6x,或者7x
  • 对于大多数西欧来说,重音字母应该是 Cxyy
  • 西里尔文,希伯来文和波斯文/阿拉伯文: Dxyy
  • 亚洲大部分地区: Exyyzz
  • 表情符号和一些中文: F0yyzzww
  • 更多细节

查明问题的具体原因和解决方法

截断文本(Sefor Señor):

  • 要存储的字节不编码为utf8mb4.解决这个问题.
  • 另外,检查读取期间的连接是否为UTF-8.

带有问号的黑色钻石(Se?orfor Señor); 其中一种情况存在:

案例1(原始字节不是 UTF-8):

  • 要存储的字节不编码为utf8.解决这个问题.
  • 的连接(或SET NAMES为)INSERT 所述SELECT不UTF8/utf8mb4.解决这个问题.
  • 另外,检查数据库中的列是否为CHARACTER SET utf8(或utf8mb4).

案例2(原始字节 UTF-8):

  • 连接(或SET NAMES)SELECT不是utf8/utf8mb4.解决这个问题.
  • 另外,检查数据库中的列是否为CHARACTER SET utf8(或utf8mb4).

只有在浏览器设置为时才会出现黑色菱形<meta charset=UTF-8>.

问号(常规,不是黑色钻石)(Se?orfor Señor):

  • 要存储的字节不编码为utf8/utf8mb4.解决这个问题.
  • 数据库中的列不是CHARACTER SET utf8(或utf8mb4).解决这个问题.(使用SHOW CREATE TABLE.)
  • 另外,检查读取期间的连接是否为UTF-8.

Mojibake(Señorfor Señor):(此讨论也适用于双重编码,不一定可见.)

  • 要存储的字节需要是UTF-8编码的.解决这个问题.
  • 连接时INSERTingSELECTing文本需要指定utf8或utf8mb4.解决这个问题.
  • 该列需要声明CHARACTER SET utf8(或utf8mb4).解决这个问题.
  • HTML应该从<meta charset=UTF-8>.

如果数据看起来正确,但无法正确排序,那么您选择了错误的排序规则,或者没有适合您需要的排序规则,或者您有双重编码.

通过执行SELECT .. HEX ..上述操作可以确认双重编码.

é should come back C3A9, but instead shows C383C2A9
The Emoji  should come back F09F91BD, but comes back C3B0C5B8E28098C2BD
Run Code Online (Sandbox Code Playgroud)

也就是说,十六进制大约应该是它的两倍.这是因为从latin1(或其他)转换为utf8,然后将这些字节视为latin1并重复转换.排序(和比较)不能正常工作,因为它是,例如,排序就像字符串一样Señor.

尽可能修复数据

对于截断问号,数据将丢失.

对于Mojibake/Double Encoding,......

对于黑钻石,......

(我将不得不在另一个问题/答案中继续这样做.)

  • [**修复**](http://mysql.rjweb.org/doc.php/charcoll#fixes_for_various_cases) (3认同)

cas*_*ira 9

在服务器迁移后,我的 2 个项目遇到了类似的问题。在搜索并尝试了很多解决方案后,我遇到了这个:

mysqli_set_charset($con,"utf8");
Run Code Online (Sandbox Code Playgroud)

将此行添加到我的配置文件后,一切正常!

当我想解决来自 html 查询的插入时,我找到了 mysqli https://www.w3schools.com/PHP/func_mysqli_set_charset.asp 的这个解决方案

祝你好运!


Ash*_*att 5

我也在寻找同样的问题。我花了近一个月的时间才找到合适的解决方案。

首先,您必须将数据库中所有最新的 CHARACTER 和 COLLATION 更新为 utf8mb4 或至少支持 UTF-8 数据。

对于Java:

在建立 JDBC 连接时,将其添加到连接 URL useUnicode=yes&characterEncoding=UTF-8作为参数,它将起作用。

对于Python:

在查询数据库之前,尝试对游标强制执行此操作

cursor.execute("SET NAMES utf8mb4")
cursor.execute("SET CHARACTER SET utf8mb4")
cursor.execute("SET character_set_connection=utf8mb4")
Run Code Online (Sandbox Code Playgroud)

如果它不起作用,请快乐寻找正确的解决方案。