GO 的鏈式呼叫寫一個轉碼庫

MervynZ發表於2018-06-14

前兩天用 GO 寫一個網站的爬蟲練手,但爬下來的內容是亂碼的,一看原來該網站是 GBK 編碼的,而 GO 中預設編碼是 UTF-8 的,所以會導致非 UTF-8 的內容是亂碼的。

於是我去找了一下 GO 的轉碼庫,主要有 mahoniaiconv-go、和官方的 golang.org/x/text 這三個庫用的比較多。

對這三個庫都使用了一下,發現都不是很滿意。下面看一下這三個庫的 GBK 轉 UTF-8。

  • mahonia
package main

import "fmt"
import "github.com/axgle/mahonia"

func main() {
	testBytes := []byte{0xC4, 0xE3, 0xBA, 0xC3, 0xA3, 0xAC, 0xCA, 0xC0, 0xBD, 0xE7, 0xA3, 0xA1}
	testStr := string(testBytes)
	enc := mahonia.NewDecoder("gbk")
	res := enc.ConvertString(testStr)
	fmt.Println(res) // 你好,世界!
}
複製程式碼
  • iconv-go
package main

import (
	"fmt"

	"github.com/axgle/mahonia"
	iconv "github.com/djimenez/iconv-go"
)

func main() {
	testBytes := []byte{0xC4, 0xE3, 0xBA, 0xC3, 0xA3, 0xAC, 0xCA, 0xC0, 0xBD, 0xE7, 0xA3, 0xA1}
	var res []byte
	iconv.Convert(testBytes, res, "GBK", "UTF-8")
	fmt.Printf(string(res)) // 你好,世界!
}
複製程式碼
  • golang.org/x/text
package main

import (
	"bytes"
	"fmt"
	"io/ioutil"

	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/transform"
)

func main() {
	testBytes := []byte{0xC4, 0xE3, 0xBA, 0xC3, 0xA3, 0xAC, 0xCA, 0xC0, 0xBD, 0xE7, 0xA3, 0xA1}
	decoder := simplifiedchinese.GBK.NewDecoder()
	reader := transform.NewReader(bytes.NewReader(testBytes), decoder)
	res, _ := ioutil.ReadAll(reader)
	fmt.Printf(string(res)) // 你好,世界!
}

複製程式碼

上面就是這三個庫的基本使用,可以發現這三個庫都有一些問題:

  • mahonia 的 API 是最簡單的,但是隻能輸入輸出 string 型別的值,而我們在 GO 中處理資料很多時候都是 []byte 或者 io.Reader 型別的,這個就比較侷限了。
  • iconv-go 可以讀取 string[]byteio.Reader 型別的資料,但底層是對 C 的 iconv 庫的封裝,在各種環境下都會出現問題,編譯時出錯也不好定位,我之前有幾次都沒裝成功:(。
  • golang.org/x/text 這是官方提供的庫,但是 API 太繁瑣了,pass。

transcode

我思索了一下,感覺鏈式呼叫是一個不錯的解決方案,於是造了一個輪子,叫做 transcode,下面看一下使用方式:

  • GBK 轉 UTF-8
package main

import (
	"fmt"

	"github.com/piex/transcode"
)

func main() {
	testBytes := []byte{0xC4, 0xE3, 0xBA, 0xC3, 0xA3, 0xAC, 0xCA, 0xC0, 0xBD, 0xE7, 0xA3, 0xA1}
	res := transcode.FromByteArray(testBytes).Decode("GBK").ToString()
	fmt.Printf(res) // 你好,世界
}
複製程式碼
  • UTF-8 轉 GBK
package main

import (
	"bytes"
	"fmt"

	"github.com/piex/transcode"
)

func main() {
	testBytes := []byte{0xC4, 0xE3, 0xBA, 0xC3, 0xA3, 0xAC, 0xCA, 0xC0, 0xBD, 0xE7, 0xA3, 0xA1}
	testStr := "你好,世界!"
	res := transcode.FromString(testStr).Encode("GBK").ToByteArray()
	fmt.Println(bytes.Equal(res, testBytes)) // true
}
複製程式碼

這個庫底層是對 golang.org/x/text 轉碼相關的 API 的一個封裝,這個是官方的庫,還是值得認可的,知識 API 太難用了,所以對這個庫進行了一個封裝,目前支援 string[]byte 資料型別的輸入輸出。

這裡使用了鏈式呼叫,主要是在最後把結構體返回就可以了。然後對 ToStringToByteArray 這兩個方法做另外的處理。

倉庫地址:github.com/piex/transc…,大家可以看一下原始碼,還很簡陋,後面還會新增對 io.Reader 型別的支援,有興趣的可以 pr。

相關文章