用 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 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) } } } }