52 lines
1.6 KiB
Go
52 lines
1.6 KiB
Go
package kb
|
||
|
||
import (
|
||
"bytes"
|
||
"unicode/utf8"
|
||
|
||
"golang.org/x/text/encoding/simplifiedchinese"
|
||
"golang.org/x/text/encoding/unicode"
|
||
)
|
||
|
||
// bytesReader 把 []byte 包装成 *bytes.Reader(excelize.OpenReader 需要 io.Reader)
|
||
//
|
||
// 单独抽出来是因为 excelize/v2 同时支持 OpenReader(io.Reader),
|
||
// 而 bytes.NewReader 是最直接的方式。
|
||
func bytesReader(data []byte) *bytes.Reader {
|
||
return bytes.NewReader(data)
|
||
}
|
||
|
||
// decodeToUTF8 把未知编码的文本字节兜底转成 UTF-8 字符串
|
||
//
|
||
// 为什么需要:国内 Windows 环境导出的 txt/csv/html 大量是 GBK 编码,
|
||
// 记事本「Unicode」格式存的是 UTF-16LE;不转码直接入库会变乱码,
|
||
// FULLTEXT 检索也永远命中不了
|
||
//
|
||
// 识别顺序:
|
||
// 1. UTF-16 BOM(FF FE = LE / FE FF = BE)→ 按 UTF-16 解码
|
||
// 2. 合法 UTF-8(剥 BOM 后)→ 原样返回
|
||
// 3. 其他 → 按 GB18030(GBK/GB2312 的超集)解码
|
||
func decodeToUTF8(data []byte) string {
|
||
if len(data) >= 2 {
|
||
if data[0] == 0xFF && data[1] == 0xFE {
|
||
if out, err := unicode.UTF16(unicode.LittleEndian, unicode.UseBOM).NewDecoder().Bytes(data); err == nil {
|
||
return string(out)
|
||
}
|
||
}
|
||
if data[0] == 0xFE && data[1] == 0xFF {
|
||
if out, err := unicode.UTF16(unicode.BigEndian, unicode.UseBOM).NewDecoder().Bytes(data); err == nil {
|
||
return string(out)
|
||
}
|
||
}
|
||
}
|
||
data = bytes.TrimPrefix(data, []byte{0xEF, 0xBB, 0xBF})
|
||
if utf8.Valid(data) {
|
||
return string(data)
|
||
}
|
||
if out, err := simplifiedchinese.GB18030.NewDecoder().Bytes(data); err == nil {
|
||
return string(out)
|
||
}
|
||
// 极端情况:连 GB18030 都解不了,原样返回(至少不丢数据)
|
||
return string(data)
|
||
}
|