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

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

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

如何更正这些字符串?

【问题讨论】:

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

标签: mysql string utf-8 character-encoding


【解决方案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
    猜你喜欢
    • 1970-01-01
    • 2016-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-06
    • 1970-01-01
    • 2012-09-09
    相关资源
    最近更新 更多