亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用 Go 解碼文本時忽略非法字節?

使用 Go 解碼文本時忽略非法字節?

Go
海綿寶寶撒 2021-11-08 14:40:00
我正在轉換一個解碼電子郵件的 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-8r := transform.NewReader(strings.NewReader(body), enc.NewDecoder())// result contains the converted-to-utf8 email bodyresult, err := ioutil.ReadAll(r)除非遇到非法字節,否則效果很好,不幸的是,這在野外處理電子郵件時并不少見。ioutil.ReadAll() 返回錯誤和所有轉換的字節,直到出現問題。有沒有辦法告訴轉換包忽略非法字節?現在,我們使用 -c 標志來 iconv 來做到這一點。我已經瀏覽了轉換包的文檔,但我不知道這是否可能。更新: 這是一個顯示問題的測試程序(Go 游樂場沒有字符集或轉換包......)。原始文本取自實際電子郵件。是的,它是英文的,是的,電子郵件中的字符集設置為 EUC-KR。我需要它來忽略那個撇號。package mainimport (    "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))}
查看完整描述

2 回答

?
湖上湖

TA貢獻2003條經驗 獲得超2個贊

enc.NewDecoder()結果是transform.Transformer. 的文檔NewDecoder()說:


轉換不屬于該編碼的源字節本身不會導致錯誤。每個無法轉碼的字節將在輸出中由 '\uFFFD' 的 UTF-8 編碼表示,替換符文。


這告訴我們是讀取器在替換符文(也稱為錯誤符文)上失敗了。幸運的是,很容易將它們剝離出來。


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)

這應該過濾掉所有符文錯誤,然后才能到達閱讀器并爆炸。


查看完整回答
反對 回復 2021-11-08
?
互換的青春

TA貢獻1797條經驗 獲得超6個贊

這是我采用的解決方案。我沒有使用 Reader,而是手動分配目標緩沖區并Transform()直接調用該函數。當Transform()錯誤出現時,我會檢查一個短的目標緩沖區,并在必要時重新分配。否則我跳過一個符文,假設它是非法字符。為完整起見,我還應該檢查短輸入緩沖區,但在本例中我沒有這樣做。


raw := `So, at 64 kBps, or kilobits per second, you’re getting 8 kilobytes a second.`

enc, _ := charset.Lookup("euc-kr")

dst := make([]byte, len(raw))

d := enc.NewDecoder()


var (

    in  int

    out int

)

for in < len(raw) {

    // Do the transformation

    ndst, nsrc, err := d.Transform(dst[out:], []byte(raw[in:]), true)

    in += nsrc

    out += ndst

    if err == nil {

        // Completed transformation

        break

    }

    if err == transform.ErrShortDst {

        // Our output buffer is too small, so we need to grow it

        log.Printf("Short")

        t := make([]byte, (cap(dst)+1)*2)

        copy(t, dst)

        dst = t

        continue

    }

    // We're here because of at least one illegal character. Skip over the current rune

    // and try again.

    _, width := utf8.DecodeRuneInString(raw[in:])

    in += width

}


查看完整回答
反對 回復 2021-11-08
  • 2 回答
  • 0 關注
  • 241 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號