我正在转换一个用于解码电子邮件的 Go 程序。它当前运行 iconv 来进行实际的解码,这当然有开销。我想使用 golang.org/x/text/transform 和 golang.org/x/net/html/charset 包来执行此操作。这是工作代码:
// cs is the charset that the email body is encoded with, pulled from
// the Content-Type declaration.
enc, name := charset.Lookup(cs)
if enc == nil {
log.Fatalf("Can't find %s", cs)
}
// body is the email body we're converting to utf-8
r := transform.NewReader(strings.NewReader(body), enc.NewDecoder())
// result contains the converted-to-utf8 email body
result, err := ioutil.ReadAll(r)
除非遇到非法字节,否则效果很好,不幸的是,在野外处理电子邮件时,这种情况并不少见。 ioutil.ReadAll() 返回错误以及出现问题之前的所有转换字节。有没有办法告诉转换包忽略非法字节?现在,我们使用 iconv 的 -c 标志来做到这一点。我已经浏览了转换包的文档,但我不知道它是否可能。
更新: 这是一个显示问题的测试程序(Go Playground 没有字符集或转换包...)。原始文本取自真实的电子邮件。是的,它是英文的,是的,电子邮件中的字符集设置为 EUC-KR。我需要它来忽略那个撇号。
package main
import (
"io/ioutil"
"log"
"strings"
"golang.org/x/net/html/charset"
"golang.org/x/text/transform"
)
func main() {
raw := `So, at 64 kBps, or kilobits per second, you’re getting 8 kilobytes a second.`
enc, _ := charset.Lookup("euc-kr")
r := transform.NewReader(strings.NewReader(raw), enc.NewDecoder())
result, err := ioutil.ReadAll(r)
if err != nil {
log.Printf("ReadAll returned %s", err)
}
log.Printf("RESULT: '%s'", string(result))
}
最佳答案
enc.NewDecoder()
结果是 transform.Transformer
。 NewDecoder()
的文档说:
Transforming source bytes that are not of that encoding will not result in an error per se. Each byte that cannot be transcoded will be represented in the output by the UTF-8 encoding of '\uFFFD', the replacement rune.
这告诉我们读取器在替换 rune (也称为错误 rune )上失败。幸运的是,很容易将它们删除。
golang.org/x/text/transform
提供了两个我们可以用来解决这个问题的辅助函数。 Chain()
接受一组变压器并将它们链接在一起。 RemoveFunc()
接受一个函数并过滤掉它返回 true 的所有字节。
类似以下内容(未经测试)应该有效:
filter := transform.Chain(enc.NewDecoder(), transform.RemoveFunc(func (r rune) bool {
return r == utf8.RuneError
}))
r := transform.NewReader(strings.NewReader(body), filter)
这应该在所有 rune 错误到达阅读器并爆炸之前过滤掉它们。
关于go - 用 Go 解码文本时忽略非法字节?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32512500/