使用 Go 和 MySQL 将 UTF8 字符串编码为 latin1/iso-8859-1

Encoding UTF8 string to latin1/iso-8859-1 with Go and MySQL

我在 table 中有一个带有德语“Umlaute öäü”的 MySQL 数据库,我需要编写一个读取 table 的 Go 应用程序,将其编码为 ISO-8859 -1 并将其写入文本文件。

到目前为止一切顺利,但 iso-8859-1 的编码不起作用。我试过调试这个。

这里有一些细节和信息:

MySQL MySQL 数据库是 UTF8,也是 table 本身。其他字符集也应该没问题,除了 character_set_server,但我认为这与这里无关,据我所知,它应该只是新数据库的默认值。

当我使用以下 SQL 查询数据库时,我得到了正确的 UTF8 编码文本:

select street, hex(street) from test_table where id = '36'

Result: (in real it is called Fröbelstraße)
Fröbelstraße, 4672C3B662656C73747261C39F65

所以从十六进制字符串来看,它基本上完全符合我的预期。好的。

去应用程序 只是相关部分....

db, err := sql.Open("mysql", "...<connection string>...")
res, err := db.Query("select street from from test_table where id = '36'")

for res.Next() {
var pb Phonebook
        err := res.Scan(&pb.Street)
        fmt.Println(hex.EncodeToString([]byte(pb.Street)))
}

输出是 4672c383c2b662656c73747261c383c5b865

这就是为什么我的 ISO-8859-1 编码不起作用的问题,因为数据库中的字符串不正确。来自 db 直接查询的十六进制是正确的并且也适用于编码。

但是我不明白为什么我从 go 客户端得到了不同的字符串。

在原始字符串“Fröbelstraße”中有 2 个字符“ö”(C3B6)和“ß”(C39F)。来自 db 客户端的查询的十六进制没问题,但是来自 go 应用程序的十六进制太长了,因为我每个字符多了 2 个字节。

当我为 latin1 转换器提供正确的十六进制字符串时,它工作正常,我得到一个 iso-8859-1 字符串。但不是从另一个我直接从 Go 查询的。

我这样做是为了

    d := charmap.ISO8859_1.NewEncoder()
    out, err := d.String(inp)

也只是一个片段,我实际上用一个字符串调用了一个函数,但我从来没有得到正确的 iso8859-1 结果。所以我用 MySQL 客户端查询中的十六进制代码进行了尝试,将其转换回字符串,结果 iso8859-1 结果正确。

我也尝试从 python 查询并从查询的字符串中得到相同的奇怪十六进制,所以我完全不知道这里有什么问题。不能去,因为在python里也是一样的。但在我看来,它在数据库中的存储是正确的,MySQL 字符集都设置为 utf8mb4 或 utf8,除了我在上面提到的那个。

彻底迷失了两天后,我自己找到了根源。奇怪的是,我在这里发布问题后不久就发生了。

我想尝试不同的 mysql 服务器,因此放弃了 table。然后我在转储中看到每个字段都有自己的字符集定义,在我的例子中是 latin1。

这就解释了为什么这是一个奇怪的结果。我刚刚创建了一个正确的编码测试 table,它现在可以正常工作了。

现在我必须考虑如何“修复”这些编码,也许 dump/restore 可以,但那是另一回事了。

4672c383c2b662656c73747261c383c5b865 似乎是“double-encoded”。在

中寻找

但是,由于您是从应用程序而不是 table 获取十六进制,所以它是不确定的。请执行 SELECT HEX(col) FROM ... 以查看您是否准确地获得了该字符串。通常,应用程序(尤其是浏览器)会尝试“修复”问题,从而使正确诊断变得更加困难。

如果你有“CHARACTER SET utf8mb4和double-encoding”,那么这个可能治愈数据:

UPDATE tbl SET col = CONVERT(BINARY(CONVERT(col USING latin1)) USING utf8mb4);

但是,您也需要修复数据源。