如何修复双编码 UTF8 字符(在 utf-8 表中)

Posted

技术标签:

【中文标题】如何修复双编码 UTF8 字符(在 utf-8 表中)【英文标题】:How to fix double-encoded UTF8 characters (in an utf-8 table) 【发布时间】:2012-07-11 07:17:17 【问题描述】:

之前的LOAD DATA INFILE 是在假设CSV 文件是latin1 编码的情况下运行的。在此导入期间,多字节字符被解释为两个单个字符,然后使用 utf-8(再次)进行编码。

这种双重编码创建了像ñ 这样的异常,而不是ñ

如何更正这些字符串?

【问题讨论】:

@Esailija 这不是 mysql 函数。无需将 php 等工具引入图片即可解决。 (这个问题是为了自我回答而创建的,但如果出现更好的解决方案,我会接受它而不是我的)。 很高兴知道,将此标记为收藏,以便我需要时可以找到它 【参考方案1】:

以下 MySQL 函数将在双重编码后返回正确的 utf8 字符串:

CONVERT(CAST(CONVERT(field USING latin1) AS BINARY) USING utf8)

它可以与UPDATE 语句一起使用来更正字段:

UPDATE tablename SET
    field = CONVERT(CAST(CONVERT(field USING latin1) AS BINARY) USING utf8);

【讨论】:

我大部分时间都在工作,但发现一个不起作用的序列:字母 ěC49B 但在我的数据库中显示为 c384c29bSELECT HEX(CONVERT(CAST(0xc384c29b AS CHAR) USING latin1)) 得到了无效的 UTF-8字节序列C43F 这意味着你最外层的CONVERT 不起作用。 UTF-8 字节 c29b 应该是 Unicode 9B 但 MySQL 将其设置为 3F (?) 大概是因为这是 latin1 中的控制字符。不过 Perl 的 utf8::decode 可以使用它。 我不能不说我很高兴我找到了这个解决方案:) 太棒了。这似乎有效。现在我的挑战是弄清楚是只有 some 记录有这个编码错误,还是全部都有。我可能只需要搜索字符不正确的记录。 哇...我正在尝试通过 PHP 完成此任务,但您节省了我的时间。 100% 在我的数据库中工作。 谢谢!每个人都应该看到Eric’s enhancement,它可以防止由于null 结果而导致的数据丢失(如果特定列已经是非ASCII utf8,即不是latin1,则可以得到)。【参考方案2】:

上面的答案适用于我的一些数据,但运行后导致很多 NULL 列。我的想法是,如果转换不成功,它会返回 null。为了避免这种情况,我加了一张小支票。

UPDATE
    tbl

SET
    col =
    CASE
        WHEN CONVERT(CAST(CONVERT(col USING latin1) AS BINARY) USING utf8) IS NULL THEN col
        ELSE CONVERT(CAST(CONVERT(col USING latin1) AS BINARY) USING utf8)
    END

【讨论】:

救了我的命!完美的!!谢谢! 防止数据丢失的一个非常重要的补充,谢谢!您可以通过将CASE WHEN converted IS NULL THEN original ELSE converted END 替换为IF(converted IS NULL, original, converted) 甚至IFNULL(converted, original) 来进一步简化此操作。【参考方案3】:

我也遇到这个问题,这里是Oracle的解决方案:

update tablename t set t.colname = convert(t.colname, 'WE8ISO8859P1', 'UTF8') where t.colname like '%Ã%'

还有一个用于 Java 的:

public static String fixDoubleEncoded(String text) 
    final Pattern pattern = Pattern.compile("^.*Ã[^0-9a-zA-Z\\ \t].*$");
    try 
        while (pattern.matcher(text).matches())
            text = new String(text.getBytes("iso-8859-1"), "utf-8");
    
    catch (UnsupportedEncodingException e) 
        e.printStackTrace();
    
    return text;

【讨论】:

【参考方案4】:

使用“utf8mb4”而不是“utf8”非常重要,因为mysql会在一个无法识别的字符之后删除所有数据。所以更安全的方法是;

UPDATE tablename SET
field = CONVERT(CAST(CONVERT(field USING latin1) AS BINARY) USING utf8mb4);

小心这个。

【讨论】:

如果你的排序规则不是 utf8mb4_unicode_ci ,首先改变这个:ALTER TABLE tablename modify fieldname type CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci

以上是关于如何修复双编码 UTF8 字符(在 utf-8 表中)的主要内容,如果未能解决你的问题,请参考以下文章

修复损坏的 UTF-8 编码

开发误区----MySQL数据库误区

如何检测和修复不正确的字符编码

如何在mysql中存取utf8mb4编码的字符

如何将4字节utf-8的emoji表情转换为unicode字符编码

我需要在拉丁语 1 --> UTF-8 中修复隐藏的编码错误吗?