解决 CSV 文件的第一列不能解析

原创 2023年 10月 25日
标签: PYTHON CSV GOLANG

先打个广告:欢迎关注我的公众号,参与 文史大挑战 趣味题目。使用方法见 这篇文章

公众号:晚花行乐

正文开始:

用 Python 或者 go 语言解析 CSV 文件的时候,有时候会遇到不能解析出第一列的情况,尤其是当这个CSV文件来自 Excel的时候,容易出现这种现象。本文试着解决这个问题。

问题描述

其实在 向 Elastic Search 中批量导入 Excel 这篇文章中已经遇到了这个问题。

看这样一个使用 Excel 软件创建的 csv 文件:

( ☝Excel 创建的 csv )

用文本编辑器打开 csv 文件,正如文本看到的是用逗号分隔的文本:

( ☝Excel 创建的 csv )

我们希望用 Python 或者 Go 语言解析这个 csv, 使用的代码如下:

使用 Python 解析

运行下面的代码用来查看每一行的内容:

import csv

with open("some.csv", 'r') as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row["Id"], row["Name"], row["Age"])

运行这段代码,会报错:找不到 Id 这个字段:

Traceback (most recent call last):
  File "some.py", line 6, in <module>
    print(row["Id"], row["Name"], row["Age"])
KeyError: 'Id'

使用 Go 解析

运行下面的代码用来寻找名字叫 Id 的文本值:

package main

import (
	"encoding/csv"
	"fmt"
	"io"
	"log"
	"os"
)

func main() {
	f, err := os.Open("some.csv")
	if err != nil {
		log.Fatalf("Error: %s", err)
	}
	defer f.Close()

	r := csv.NewReader(f)

	for {
		record, err := r.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Fatalf("Read csv error: %s", err)
		}
		for _, field := range record {
			if field == "Id" {
				fmt.Println(field)
			}
		}

	}
}

得到结果为空,什么也不打印。

问题原因

用 16进制编辑器查看文件,会发现文件头有三个字节的 BOM 字符:

如果解析 csv 的库不去主动处理这三个字符,就会被当作第一个字段名的一部分。

Python 的解决方法

在打开文件的 open 函数中,指定解码方式为 encoding='utf_8_sig'

import csv

with open("some.csv", 'r', encoding='utf_8_sig') as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row["Id"], row["Name"], row["Age"])

顺利读出 csv 文件的结构:

1 Alice 12
2 Bob 8
3 Charlie 10

Go 语言的解决方法

使用第三方库 utfbom,可以方便的去掉 BOM 字符:

go get -u github.com/dimchansky/utfbom

原生 csv 库


package main

import (
	"encoding/csv"
	"fmt"
	"io"
	"log"
	"os"

	"github.com/dimchansky/utfbom"
)

func main() {
	f, err := os.Open("some.csv")
	if err != nil {
		log.Fatalf("Error: %s", err)
	}
	defer f.Close()

	r := csv.NewReader(utfbom.SkipOnly(f))

	for {
		record, err := r.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Fatalf("Read csv error: %s", err)
		}
		for _, field := range record {
			if field == "Id" {
				fmt.Println(field)
			}
		}

	}
}

如果您对本文有疑问或者寻求合作,欢迎 联系邮箱邮箱已到剪贴板

标签: PYTHON CSV GOLANG
给个免费的赞吧~

精彩评论

本站 是个人网站,采用 署名协议 CC-BY-NC 授权。
欢迎转载,请保留原文链接 https://www.lfhacks.com/tech/unable-to-unmarshal-first-column-of-csv/ ,且不得用于商业用途。