質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Q&A

解決済

1回答

16724閲覧

[go] utf8からsjisへの変換で"rune not supported by encoding"エラー

退会済みユーザー

退会済みユーザー

総合スコア0

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

0グッド

0クリップ

投稿2017/12/23 00:37

問題

GoでSJISでCSVを書き出す際に"rune not supported by encoding"というエラーが発生して、CSVが正常に出力されない。

環境

go version go1.9.2 windows/amd64

コード

go

1package main 2 3import ( 4 "encoding/csv" 5 "fmt" 6 "log" 7 "os" 8 9 "golang.org/x/text/encoding/japanese" 10 "golang.org/x/text/transform" 11) 12 13const ( 14 NO_BREAK_SPACE = "\u00A0" 15 WAVE_DASH = "\u301C" 16) 17 18func main() { 19 file, err := os.Create("out.csv") 20 if err != nil { 21 log.Fatal(err) 22 panic(err) 23 } 24 defer file.Close() 25 26 writer := csv.NewWriter(transform.NewWriter(file, japanese.ShiftJIS.NewEncoder())) 27 writer.UseCRLF = true 28 29 header := []string{ 30 "header1", 31 "header2", 32 } 33 body := []string{ 34 fmt.Sprintf("あ%sい", utils.NO_BREAK_SPACE), 35 fmt.Sprintf("十時 %s 十二時", utils.WAVE_DASH), 36 } 37 38 err = writer.Write(header) 39 if err != nil { 40 log.Println(err) 41 } 42 43 err = writer.Write(body) 44 if err != nil { 45 log.Println(err) 46 } 47 48 writer.Flush() 49 err = writer.Error() 50 if err != nil { 51 log.Println(err) // encoding: rune not supported by encoding. 52 } 53}

出力されるCSV

sjisで以下のように出力されます

csv

1header1,header2 2

質問

上記の現象はUTF8には存在するがSJISに存在しない文字を変換した際に起こるものだと思っています。

go

1 2func main() { 3 iostr := strings.NewReader(WAVE_DASH) 4 rio := transform.NewReader(iostr, japanese.ShiftJIS.NewEncoder()) 5 ret, err := ioutil.ReadAll(rio) 6 log.Println(ret) // [] 7 log.Println(err) // encoding: rune not supported by encoding. 8}

SJISに変換する前にSJISに存在しない文字は?に置換するというのが一般的な方法だと思うのですが、nkfやiconvなどを使用せずにgoの標準ライブラリのみで対応できるのでしょうか?

よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

変換できない文字を ? で描き直す Writer で wrap してあげれば良いかと思います。

go

1package main 2 3import ( 4 "encoding/csv" 5 "fmt" 6 "io" 7 "log" 8 "os" 9 "unicode/utf8" 10 11 "golang.org/x/text/encoding/japanese" 12 "golang.org/x/text/transform" 13) 14 15const ( 16 NO_BREAK_SPACE = "\u00A0" 17 WAVE_DASH = "\u301C" 18) 19 20type runeWriter struct { 21 w io.Writer 22} 23 24func (rw *runeWriter) Write(b []byte) (int, error) { 25 var err error 26 l := 0 27 28loop: 29 for len(b) > 0 { 30 _, n := utf8.DecodeRune(b) 31 if n == 0 { 32 break loop 33 } 34 _, err = rw.w.Write(b[:n]) 35 if err != nil { 36 _, err = rw.w.Write([]byte{'?'}) 37 if err != nil { 38 break loop 39 } 40 } 41 l += n 42 b = b[n:] 43 } 44 return l, err 45} 46 47func main() { 48 file, err := os.Create("out.csv") 49 if err != nil { 50 log.Fatal(err) 51 panic(err) 52 } 53 defer file.Close() 54 55 writer := csv.NewWriter( 56 &runeWriter{transform.NewWriter(file, japanese.ShiftJIS.NewEncoder())}) 57 writer.UseCRLF = true 58 59 header := []string{ 60 "header1", 61 "header2", 62 } 63 body := []string{ 64 fmt.Sprintf("あ%sい", NO_BREAK_SPACE), 65 fmt.Sprintf("十時 %s 十二時", WAVE_DASH), 66 } 67 68 err = writer.Write(header) 69 if err != nil { 70 log.Fatal(err) 71 } 72 73 err = writer.Write(body) 74 if err != nil { 75 log.Fatal(err) 76 } 77 78 writer.Flush() 79 err = writer.Error() 80 if err != nil { 81 log.Fatal(err) // encoding: rune not supported by encoding. 82 } 83}

投稿2017/12/25 06:11

mattn

総合スコア5030

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/12/25 13:33

mattnさんありがとうございました! なるほどGoではこのように対応できるのですね。 Rubyのようにライブラリや言語がたくさんの機能を持つのではなく、 自分でカスタマイズして使っていくという点がGoらしさなのかなと印象を受けました。 ありがとうございます、勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問