1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

gocsvですべてのセルをダブルクォーテーションで囲む

Posted at

概要

gocsvで生成するCSVのすべてのセルをダブルクォーテーションで囲みたかった。
ネットで見つけた記事とは別パターンの実装をしてみた。

実装

方針

ネットで見つけた記事では、生成したCSVをデコードして、各セルをダブルクォーテーションで囲った後、もう一度エンコードしている。

自分は、以下の方法で実装してみた。
gocsvでは、デフォルトでは内部でencoding/csvのWriter構造体を使用している。そこで、

  1. gocsvのCSVWriterインターフェイスを実装する構造体を作成する
  2. ↑で作成した構造体に、encoding/csvのWriterの実装を参考に、すべてのセルをダブルクォーテーションで囲むWriteメソッドを生やす
  3. ↑をgocsvのMarshalCSVメソッドに渡す

gocsvのCSVWriterインターフェイス

type CSVWriter interface {
	Write(row []string) error
	Flush()
	Error() error
}

↑を実装するカスタム構造体

type customCSVWriter struct {
	w *bufio.Writer
}

func NewCustomCSVWriter(w io.Writer) gocsv.CSVWriter {
	return &customCSVWriter{
		w: bufio.NewWriter(w),
	}
}

// Write writes すべてのセルをダブルクォーテーションで囲んだCSV
// encoding/csvのWriteメソッド(https://cs.opensource.google/go/go/+/refs/tags/go1.19.2:src/encoding/csv/writer.go;l=48)を一部改修したもの
// 違いは以下
// 1. すべてのセルをダブルクォーテーションで囲む
// 2. 区切り文字は`,`固定
// 3. 改行文字に`\r\n`を使用するオプションは無効
func (w *customCSVWriter) Write(record []string) error {
	for n, field := range record {
		if n > 0 {
			if _, err := w.w.WriteRune(','); err != nil {
				return err
			}
		}

		if err := w.w.WriteByte('"'); err != nil {
			return err
		}
		for len(field) > 0 {
			// Search for special characters.
			i := strings.IndexAny(field, "\"\r\n")
			if i < 0 {
				i = len(field)
			}

			// Copy verbatim everything before the special character.
			if _, err := w.w.WriteString(field[:i]); err != nil {
				return err
			}
			field = field[i:]

			// Encode the special character.
			if len(field) > 0 {
				var err error
				switch field[0] {
				case '"':
					_, err = w.w.WriteString(`""`)
        case '\r':
          err = w.w.WriteByte('\r')
				case '\n':
          err = w.w.WriteByte('\n')
				}
				field = field[1:]
				if err != nil {
					return err
				}
			}
		}
		if err := w.w.WriteByte('"'); err != nil {
			return err
		}
	}

	err := w.w.WriteByte('\n')
	return err
}

func (w *customCSVWriter) Flush() {
	w.w.Flush()
}

func (w *customCSVWriter) Error() error {
	_, err := w.w.Write(nil)
	return err
}

↑を呼び出すコード

buffer := bytes.Buffer{}
csvWriter := NewCustomCSVWriter(&buffer)
err := gocsv.MarshalCSV(&(CSVにしたい構造体など), csvWriter)

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?