📘

【Go】UTF-8でないCSVを取り扱う時の注意点

に公開

はじめに

Excel等で作られたCSVファイルは、Shift-JISでエンコードされていることが多々あります。
しかし、GoではUTF-8として扱うことが前提であるため、そのまま扱うと文字化けが起こってしまいます。
今回は、UTF-8ではないエンコード方式のCSVファイルを扱う方法を見ていきます。

この記事でわかること

  • UTF-8ではないCSVファイルをそのまま扱うと起きること
  • UTF-8に変換してCSVファイルを読み込む方法

UTF-8ではないCSVファイルをそのまま扱ってみる

今回はShift-JISでエンコードされたCSVファイルをそのまま扱ってみようと思います。
CSVファイルは以下のものを使います。

csvファイル
1,�R�c���Y,30,����
2,��؉Ԏq,25,���

# nkf -g example_sjis.csv
Shift_JIS

CSVを読み込み、レコードを標準出力するという簡単な実装を例に見ていきましょう。

main.go
func main() {
    f, err := os.Open("example_sjis.csv")
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    
    csvReader := csv.NewReader(f)
    csvReader.FieldsPerRecord = -1
    for {
        record, err := csvReader.Read()
        if err == io.EOF {
          break
        }
        if err != nil {
          log.Fatal(err)
        }
        fmt.Println(record)
    }
}

実行すると、以下のように出力されます。

ターミナル
# go run main.go

[1 �R�c���Y 30 ����]
[2 ��؉Ԏq 25 ���]

エンコード方式が異なるため、文字化けが起こったまま出力されていることがわかります。

UTF-8に変換してCSVファイルを扱ってみる

ここでは、Shift-JISUTF-8に変換して読み込んでみようと思います。

main.go
func main() {
	f, err := os.Open("example_sjis.csv")
	if err != nil {
		log.Fatal(err)
	}
    defer f.Close()

    // CSVデータをShift-JISからUTF-8に変換するReaderを作成
    reader := transform.NewReader(f, japanese.ShiftJIS.NewDecoder())
	csvReader := csv.NewReader(reader)
	csvReader.FieldsPerRecord = -1
	for {
        record, err := csvReader.Read()
        if err == io.EOF {
          break
        }
        if err != nil {
          log.Fatal(err)
        }
    fmt.Println(record)
  }
}

実行すると、以下のように出力されます。

ターミナル
# go run main.go

[1 山田太郎 30 東京]
[2 鈴木花子 25 大阪]

今回は、golang.org/x/text/encoding/japanesegolang.org/x/text/transformというパッケージとそこで定義されているメソッドを使いました。以下に、それぞれのパッケージやメソッドについて超概説を記載します。

1. golang.org/x/text/encoding/japanese

これは、日本語テキストをエンコーディングを扱うためのパッケージです。
NewDecoder()を使うことで、Shift_JISEUC-JPISO-2022-JPなどをUTF-8に変換するよう指定することができます。

2. golang.org/x/text/transform

これは、テキストデータの変換処理を行うための基盤パッケージです。
NewReader()を使うことで、指定したTransformer(変換ルール)を使って、io.Readerから読み込むデータを変換しながら返すReaderを生成することができます。

まとめ

今回はUTF-8ではないCSVファイルをUTF-8に変換して読み込む方法について見ていきました。
ポイントを整理すると以下の通りです。

  • Goの文字列はUTF-8前提であるため、Shift_JISEUC-JPなどの文字コードのまま読み込むと文字化けが起こる
  • golang.org/x/text/encoding/japaneseNewDecoder()を使うことで、Shift_JISなどの日本語文字コードをUTF-8に変換できる
  • golang.org/x/text/transformNewReader()を使うことで、ファイルやストリームを読み込む際に変換処理を適用したReaderを作れる
  • 変換済みのReadercsv.NewReader()に渡すことで、CSVデータを正しくUTF-8として解析・処理できる

この方法を使えば、Shift_JISなどの非UTF-8エンコードのCSVファイルも、Goで安全に読み込み・処理できるようになります。Excelなどで作成されたCSVを扱う際には、文字コード変換を意識して処理することが重要です。

参考

Discussion