19

我即将承担将数据库从 Latin1 转换为 UTF-8 的繁琐且充满陷阱的任务。

此时,我只想检查我的表中存储了哪些类型的数据,因为这将决定我应该使用哪种方法来转换数据。

具体来说,我想检查 Latin1 列中是否有 UTF-8 字符,最好的方法是什么?如果只有几行受到影响,那么我可以手动修复它。

选项 1. 执行 MySQL 转储并使用 Perl 搜索 UTF-8 字符?

选项 2. 使用 MySQL CHAR_LENGTH 查找具有多字节字符的行?例如SELECT name FROM clients WHERE LENGTH(name) != CHAR_LENGTH(name); ,这就够了吗?

目前我已将 Mysql 客户端编码切换为 UTF-8。

4

4 回答 4

55

字符编码,就像时区一样,是问题的源头。

您可以做的是查找任何“高 ASCII”字符,因为这些字符要么是 LATIN1 重音字符或符号,要么是 UTF-8 多字节字符的第一个字符。除非你稍微作弊,否则分辨出其中的差别并不容易。

要弄清楚哪种编码是正确的,您只需SELECT两个不同的版本并进行视觉比较。这是一个例子:

SELECT CONVERT(CONVERT(name USING BINARY) USING latin1) AS latin1, 
       CONVERT(CONVERT(name USING BINARY) USING utf8) AS utf8 
FROM users 
WHERE CONVERT(name USING BINARY) RLIKE CONCAT('[', UNHEX('80'), '-', UNHEX('FF'), ']')

这变得异常复杂,因为 MySQL regexp 引擎似乎忽略了类似的东西\x80,因此有必要使用该UNHEX()方法。

这会产生如下结果:

latin1                utf8
----------------------------------------
Björn                Björn
于 2012-02-16T03:52:45.540 回答
10

由于您的问题并不完全清楚,让我们假设一些情况:

  1. 迄今为止错误的连接:您一直使用 latin1 编码错误地连接到数据库,但在数据库中存储了 UTF-8 数据(在这种情况下,列的编码无关紧要)。这就是我在这里描述的情况。在这种情况下,很容易解决:通过 latin1 连接将数据库内容转储到文件中。这会将错误存储的数据转换为错误正确存储的 UTF-8,这是迄今为止的工作方式(请阅读前面链接的文章了解血腥细节)。然后,您可以通过正确设置的 utf8 连接将数据重新导入数据库,并将按原样存储。
  2. 迄今为止错误的列编码: UTF-8 数据通过 utf8 连接插入到 latin1 列中。在那种情况下算了,数据就没了。任何非 latin1 字符都应替换为?.
  3. 到目前为止一切都很好,此后增加了对 UTF-8 的支持:您将 Latin-1 数据正确存储在 latin1 列中,通过 latin1 连接插入,但想要扩展它以也允许 UTF-8 数据。在这种情况下,只需将列编码更改为 utf8。MySQL 将为您转换现有数据。然后只需确保在插入 UTF-8 数据时将数据库连接设置为 utf8。
于 2012-02-16T05:51:13.690 回答
2

github上有一个脚本可以帮助解决这类事情。

于 2013-01-28T19:29:41.800 回答
0

我将为所有有效的 UTF8 序列创建数据库和 grep 的转储。从那里拿它取决于你得到什么。SO上有多个关于识别无效UTF8的问题;你基本上可以颠倒逻辑。

编辑:所以基本上,任何完全由 7 位 ASCII 组成的字段都是安全的,任何包含无效 UTF-8 序列的字段都可以假定为 Latin-1。应该检查剩余的数据 - 如果幸运的话,少数明显的替换将修复绝对多数(将 ö 替换为 Latin-1 ö 等)。

于 2012-02-16T05:34:26.463 回答