注册 登录

清河洛

Go中的编码转换

qingheluo2025-03-07清河洛79
在使用Go处理文本(如网页)时,会遇到编码问题,Go的默认编码是UTF-8,遇到其他编码的字符会出错,此时需要对文本进行转换在Go的官方库中没有编码转换相关库,但是在golang.org/x中有相关现实的库golang.org/x 是 Go 官方团队维护的一个扩展库集合,提供了许多标准库之外的实用功能和工具,虽然不属于Go标准库,但大多数库已经经过广泛测试和使用,具备较高的稳定性和可靠性golang.org/x/text/transform是用于处理文本转换的工具,为文本的编码转换、规范化、过滤等操作提供一个统一的接口和实现框架type Transformer type Transfor...

在使用Go处理文本(如网页)时,会遇到编码问题,Go的默认编码是UTF-8,遇到其他编码的字符会出错,此时需要对文本进行转换

在Go的官方库中没有编码转换相关库,但是在golang.org/x中有相关现实的库

golang.org/x 是 Go 官方团队维护的一个扩展库集合,提供了许多标准库之外的实用功能和工具,虽然不属于Go标准库,但大多数库已经经过广泛测试和使用,具备较高的稳定性和可靠性

golang.org/x/text/transform

是用于处理文本转换的工具,为文本的编码转换、规范化、过滤等操作提供一个统一的接口和实现框架

type Transformer

type Transformer interface {
    Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error)
    Reset()
        // 重置状态,如清空所有缓冲区、错误信息等
}
Transform()
    将从src读取的字节转换后写入dst,返回写入dst字节数和读取src字节数
    atEOF表示是否读取完成
    src参数是大小不固定的[]byte,调用方(如transform.Reader)会根据其内部逻辑决定每次读取多少数据到src
    nDst和nSrc反映的是单次调用中处理的字节数,而不是整个转换过程中累计处理的字节数
    预定义错误
        ErrShortDst表示dst太短,无法接收所有转换后的字节
        ErrShortSrc表示src没有足够的数据来完成转换

包级方法

Append(t Transformer, dst, src []byte) (result []byte, n int, err error)
    使用 t 将 src转换的结果追加到 dst
    result表示src转换后的结果,即追加到dst中的数据
    n表示src中成功转换的长度,如err为nil则n等于len(src)

Bytes(t Transformer, b []byte) (result []byte, n int, err error)
    使用 t 将 b 转换,返回转换后的结果

String(t Transformer, s string) (result string, n int, err error)
    使用 t 将 字符串s转换,返回转换后的结果字符串

Chain(t ...Transformer) Transformer
    返回一个链式应用所有传入Transformer的Transformer

type NopResetter

用于在实现Transformer接口时嵌入以实现Reset()方法

type NopResetter struct{}
func (NopResetter) Reset()

该结构体的Reset方法没有进行任何操作,仅仅是为了实现接口

type Reader

type Reader struct {}

包装一个io.Reader,用来转换读取的字节

NewReader(r io.Reader, t Transformer) *Reader
    通过 t 转换读取的 r 中的字节

(r *Reader) Read(p []byte) (int, error)
    实现 io.Reader 接口

type Writer

type Writer struct {}

包装一个io.Writer,将要写入的字节转换后写入

NewWriter(w io.Writer, t Transformer) *Writer
    通过 t 将写入的数据转换后写入 w

(w *Writer) Close() error   实现了io.Closer接口

(w *Writer) Write(data []byte) (n int, err error)
    实现了 io.Writer 接口
    如果可用字节数不足以完成Transform,则字节将被缓冲以供下一次写入
    调用Close()以转换剩余的字节

golang.org/x/text/encoding

定义了用于UTF-8和其他字符编码相互转换的接口

type Decoder

解码器,用于将其他编码转换为UTF-8

type Decoder struct {
    transform.Transformer
        // 实现了transform.Transformer接口
}

常用方法

Bytes(b []byte) ([]byte, error)
    将给定的编码字节转换为 UTF-8。如果发生任何错误,则返回转换后的字节或 nil,以及错误

Reader(r io.Reader) io.Reader
    包装一个 Reader 以解码其字节
    解码器在返回的Reader使用期间不得用于任何其他操作

String(s string) (string, error)
    将给定的编码字符串转换为 UTF-8。如果发生任何错误,则返回转换后的字符串或空字符串,以及错误

type Encoder

编码器,用于将UTF-8转换为其他编码

type Encoder struct {
    transform.Transformer
        // 实现了transform.Transformer接口
}

常用方法

Bytes(b []byte) ([]byte, error)
    将UTF-8转换为给定的编码字节。如果发生任何错误,返回转换后的字节或 nil,以及错误

Writer(w io.Writer) io.Writer
    包装一个 Writer 以编码为其他编码
    编码器在返回的 Writer 被使用期间,不得用于任何其他操作

String(s string) (string, error)
    将UTF-8字符串转换为给定的编码。如果发生任何错误,则返回转换后的字符串或空字符串,以及错误

type Encoding

编码方式,是一种可以将字符集编码由UTF-8和其他编码互相转换的方式

type Encoding interface {
    NewDecoder() *Decoder
    NewEncoder() *Encoder
}

预定义编码方式

var Replacement Encoding = replacement{}
    替换编码,该包的默认编码方式
    在解码时遇到无效的UTF-8字节时会替换为'\uFFFD'
    要提前返回错误,请使用`transform.chain`与`UTF8Validator`预处理数据。

var Nop Encoding = nop{}
    在解码时遇到无效的UTF-8字节时不进行替换

golang.org/x/text/encoding/simplifiedchinese

实现了简体中文编码方式

具体的实现我们无需考虑,通过预定于的变量使用即可

var (
    GB18030 encoding.Encoding = &gbk18030
    GBK encoding.Encoding = &gbk
)


GB2312  1980年,中国发布了第一个汉字编码标准GB2312
        共收录了6763个常用的汉字和字符并于次年5月实施

GBK     1995年,在GB2312的基础上添加了部分字符形成了GBK
        共收录了两万多个汉字和字符并完全兼容GB2312
        新增字符:在GB2312标准发布之后简化的汉字、一些人名、繁体字、日语和朝鲜语中的汉
        GBK只是 "技术规范指导性文件",并不属于国家标准

GB18030 在GBK的基础上增加了中日韩语中的汉字和少数名族的文字及字符,完全兼容GB2312,基本兼容GBK
        共收录七万多个汉字和字符
        发布过两个版本,第一版于2000年发布,称为GB18030-2000,第二版于2005年发布,称为GB18030-2005

golang.org/x/net/html/charset

为HTML文档提供了常见的文本编码操作方法

DetermineEncoding(content []byte, contentType string) (e encoding.Encoding, name string, certain bool)
    根据content和contentType来推断编码
    e表示推断的字符编码方式,如无法确定返回nil
    name表示推断的字符编码名称,如"utf-8"、"gbk",无法确定返回空字符串
    certain表示推断结果是否可信,为false表示推荐可能不准确或无法确定
    编码推断步骤:
        1、分析contentType,如果存在"charset=utf-8"字样则直接返回
        2、分析content中是含有"charset=utf-8"字样的meta标签
        3、分析content的前1024个字节
        以上步骤只要找到一个就不会继续下面的步骤

Lookup(label string) (e encoding.Encoding, name string)
    根据label字符串中的特征字符串来推断编码
    如html中的,响应头中Content-Type头的值等

NewReader(r io.Reader, contentType string) (io.Reader, error)
    返回一个 io.Reader,将 r 的内容转换为 UTF-8
    会调用 DefineEncoding 推断 r 的字符编码

NewReaderLabel(label string, input io.Reader) (io.Reader, error)
    返回一个将label字符串转换为 UTF-8 的io.Reader
    它调用 Lookup 推断 label 的字符编码
    如果 Lookup 返回 nil,则返回错误


网址导航