golang utf-16le 编码转换至 utf-8
最近工作中在做解析港股数据相关工作, 香港交易所提供的 OMD-MMDH 服务将数据以字节流的形式下发, 其中汉字使用 utf16 编码, 而 golang 程序则默认 utf8 编码, 所以需要对数据做转换, 特此对 Unicode 相关知识以及 golang 实现 utf16 转换至 utf8 的方法做下学习笔记
BOM 简介
BOM(Byte Order Mark) 既字节序标记, 一般是出现在以 Unicode 编码的文件开始的头部. 带 BOM 的 Unicode 编码文件查看其二进制编码会出现以下数据, 下面只是一些常用的字符编码
字符编码 | Bom (十六进制) |
---|---|
UTF-8 | EF BB BF |
UTF-16 (BE) 大端序 | FE FF |
UTF-16 (LE) 小端序 | FF FE |
UTF-32 (BE) 大端序 | 00 00 FE FF |
UTF-32 (LE) 小端序 | FF FE 00 00 |
GB-18030 | 84 31 95 33 |
Unicode 编码简介
Unicode 是容纳世界所有文字符号的国际标准编码, 使用四个字节为每个字符编码.
UTF 是英文 Unicode Transformation Format 的缩写, 意为把 Unicode 字符转换为某种格式. UTF 系列编码方案 (UTF-8,UTF-16,UTF-32) 均是由 Unicode 编码方案衍变而来, 以适应不同的数据存储或传递, 它们都可以完全表示 Unicode 标准中的所有字符. 目前, 这些衍变方案中 UTF-8 被广泛使用, 而 UTF-16 和 UTF-32 则很少被使用.
UTF-8 使用一至四个字节为每个字符编码, 其中大部分汉字采用三个字节编码, 少量不常用汉字采用四个字节编码. 因为 UTF-8 是可变长度的编码方式, 相对于 Unicode 编码可以减少存储占用的空间, 所以被广泛使用.
UTF-16 使用二或四个字节为每个字符编码, 其中大部分汉字采用两个字节编码, 少量不常用汉字采用四个字节编码. UTF-16 编码有大端序和小端序之别, 即 UTF-16BE 和 UTF-16LE, 在编码前会放置一个 U+FEFF 或 U+FFFE(UTF-16BE 以 FEFF 代表, UTF-16LE 以 FFFE 代表), 其中 U+FEFF 字符在 Unicode 中代表的意义是 ZERO WIDTH NO-BREAK SPACE, 顾名思义, 它是个没有宽度也没有断字的空白.
UTF-32 使用四个字节为每个字符编码, 使得 UTF-32 占用空间通常会是其它编码的二到四倍. UTF-32 与 UTF-16 一样有大端序和小端序之别, 编码前会放置 U+0000FEFF 或 U+0000FFFE 以区分.
大端序和小端序
大端: 大端就是内存中的低位地址存放对应整数的高位.
小端: 小端就是内存中的低位地址存放对应整数的低位.
字节数组:[0 1 2]
按照大端序转换成二进制为:
0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 1 | 0 0 0 0 0 0 1 0
按照小端序转换成二进制为:
0 0 0 0 0 0 1 0 | 0 0 0 0 0 0 0 1 | 0 0 0 0 0 0 0 0
所以字节数组 [0 1 2] 大端序十进制为: 258, 小端序为: 131328
golang 中的转换实现参考 binary 包
golang 转换 utf-16 编码至 utf-8
utf-16 在做转换时不能忽视该编码的大端序和小端序区别, 不然将会导致乱码, 转换使用到包 golang.org/x/text/encoding/unicode,
- bs := [8]byte{
- 93, 78, 95, 134, 75, 144, 26, 144
- }
- decoder := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewDecoder()
- bs2, err := decoder.Bytes(bs[:])
- fmt.Println(string(bs2), err)
output...
九號運通 <nil>
unicode.LittleEndian 指定为小端序
unicode.IgnoreBOM 忽略 BOM 标记
参考链接:
Unicode 简介 https://www.qqxiuzi.cn/bianma/Unicode-UTF.php
BOM 简介
unicode - GoDoc
来源: https://juejin.im/post/5c70a9e651882562962eea75