读取之前清洁CSV文件。

huangapple go评论91阅读模式
英文:

Cleaning CSV file before reading

问题

我正在使用encoding/csv库读取一个大型的CSV文件。

但是这个文件有点非标准,包含了非转义的引号",导致在parser.Read()处出现错误:
>2022/06/09 17:33:54 第2行第5列解析错误:引号在引用字段中多余或缺失

如果我使用parser.LazyQuotes = true,则会得到:
>2022/06/09 17:34:15 第2行记录:字段数量错误

有问题的CSV文件(已简化为最小)foo.csv

1|2
"a|b

因此,我需要删除所有的双引号",我目前是在终端上使用sed 's/"//g'对整个文件进行操作,但我希望在Go脚本中进行删除。

在我读取文件的情况下,应该如何做到这一点:

func processCSV(filepath string){
	file, err := os.Open("foo.csv")
	if err != nil {
		log.Fatal(err)
	}

	parser := csv.NewReader(file)
	parser.Comma = '|'
    // parser.LazyQuotes = true

	_, err = parser.Read() // 跳过标题

	for {
		record, err := parser.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Fatal(err)
		}

        // 处理记录

    }
}
英文:

I'm reading a big CSV file with encoding/csv library.

But this file is a bit non-standard and contains non-escaped quotes " breaking the reader at parser.Read():
>2022/06/09 17:33:54 parse error on line 2, column 5: extraneous or missing " in quoted-field

And if I use parser.LazyQuotes = true, I'm getting:
> 2022/06/09 17:34:15 record on line 2: wrong number of fields

Faulty CSV file (reduced to its minimum) foo.csv:

1|2
"a|b

So I need to remove all occurences of double quotes " and I'm currently doing it on the whole file from terminal using sed 's/"//g', but I want to remove it from Go script instead.

How should I do it knowing that I'm reading the file like this:

func processCSV(filepath string){
	file, err := os.Open("foo.csv")
	if err != nil {
		log.Fatal(err)
	}

	parser := csv.NewReader(file)
	parser.Comma = '|'
    // parser.LazyQuotes = true

	_, err = parser.Read() // skip headers

	for {
		record, err := parser.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Fatal(err)
		}

        // process record

    }
}

答案1

得分: 3

创建一个io.Reader,通过底层的io.Reader读取的数据中去除引号。

// rmquote 从r中读取数据时去除引号。
type rmquote struct {
	r io.Reader
}

func (c rmquote) Read(p []byte) (int, error) {
	n, err := c.r.Read(p)

	// i是下面循环的输出位置
	i := 0

	// 对于从文件中读取的每个字节
	for _, b := range p[:n] {

		// 跳过引号
		if b == '"' {
			continue
		}

		// 将字节复制到输出位置并移动位置
		p[i] = b
		i++
	}

	// 输出位置就是新的长度
	return i, err
}

// 在CSV读取器和文件之间使用它:
parser := csv.NewReader(rmquote{file})
英文:

Create an io.Reader that removes quotes from data read through an underlying io.Reader.

// rmquote reads r with " removed.
type rmquote struct {
	r io.Reader
}

func (c rmquote) Read(p []byte) (int, error) {
	n, err := c.r.Read(p)

    // i is output position for loop below
	i := 0

    // for each byte read from the file
	for _, b := range p[:n] {

        // skip quotes
		if b == '"' {
			continue
		}

        // copy byte to output position and advance position
		p[i] = b
		i++
	}

    // output position is the new length
	return i, err
}

Plumb it in between the CSV reader and file:

parser := csv.NewReader(rmquote{file})

huangapple
  • 本文由 发表于 2022年6月9日 23:41:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/72563139.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定