今天在网上遇到一个问题,觉得挺有意思,就帮人解答了。
需求
在编码为Latin1的MySQL数据库中插入中文数据,由另一个系统将Latin1编码的字符串转码为GBK后作为短信内容发出。
简单版解答
import (
"golang.org/x/text/encoding/charmap"
"golang.org/x/text/encoding/simplifiedchinese"
)
func Convert(src string) (string, error) {
gbk, err := simplifiedchinese.GBK.NewEncoder().Bytes([]byte(src))
if err != nil {
return "", err
}
latin1, err := charmap.ISO8859_1.NewDecoder().Bytes(gbk)
if err != nil {
return "", err
}
return string(latin1), nil
}
解析
Latin1即ISO-8859-1,抄一段介绍 ,详见百度百科
因为ISO-8859-1编码范围使用了单字节内的所有空间,在支持ISO-8859-1的系统中传输和存储其他任何编码的字节流都不会被抛弃。换言之,把其他任何编码的字节流当作ISO-8859-1编码看待都没有问题。这是个很重要的特性,MySQL数据库默认编码是Latin1就是利用了这个特性。ASCII编码是一个7位的容器,ISO-8859-1编码是一个8位的容器。
首先说一下处理编码问题的原则:保证写和读都使用同一套规则。
依照这个原则处于中间环节的数据库不支持中文的问题怎么处理,要先看对方系统怎么读数据:
将Latin1编码的字符串转码为GBK后作为短信内容
那么我们任务就是:
将短信内容以GBK编码强制转码为ISO-8859-1然后存入数据库
清楚了任务,后面就是实现了。
UTF8->GBK,Golang是UTF8编码的,那么首先转码GBK。这里需要注意的一点是不能用Encoder.String()方法,因为这样会强制将已经编码的GBK字节流用Golang内置的UTF8 Decoder解码,而这样得到的乱码string将无法还原回原本的GBK字节流。
GBK字节流强制转ISO-8859-1字节流,怎么做呢?就是什么都不做。。。
ISO-8859-1字节流->UTF8 string,我不是很确定如何在SQL中提交[]byte,那么一个保守的做法就是先将ISO-8859-1转码为UTF8,然后由数据库驱动将UTF8转回ISO-8859-1提交。
还有一点可以提一下,由于ISO-8859-1不支持中文,所以直接提交UTF8中文,数据库驱动会直接将中文替换为?。