今天在使用Python读取CSV文件的时候,出现了一个KeyError的错误的,这个错误提示很明显,就是没有对应的列名,但是经过检查我的CSV文件中是有对应的列名的呀,然后编码格式我也检查了,这个时候我就想先打印列名看下,打印后就看出问题了。
问题原因
假设通过Excel打开我的CSV文件,列名是:列名1、列名2…
但是打印出的结果是如下:
[‘\ufeff列名1’, ‘列名2’, ‘列名3’, ‘列名4’]
我看可以看到列名1开头是\ufeff,怪不得对不上呢。知道了原因所在,我们就好解决了。
\ufeff解释
\ufeff’是Unicode字节顺序标记(BOM),它可能是在你的CSV文件被保存时添加的。你可以在读取CSV文件时忽略BOM,或者在引用列名时包含BOM(直接使用’\ufeff列名1)。
问题解决
忽略BOM解决
我们可以指定使用utf-8-sig编码格式打开来忽略bom,示例代码:
with open(filename, 'r', errors='ignore', encoding='utf-8-sig') as f:
pass
utf-8和utf-8-sig的区别
在Python中,utf-8和utf-8-sig是两种不同的文本编码方式。
utf-8是一种非常常见的文本编码方式,它可以编码所有的Unicode字符。当你使用utf-8编码打开文件时,Python会按照utf-8编码来读取文件中的字符。
utf-8-sig是utf-8的一个变体,它用于处理包含UTF-8字节顺序标记(BOM)的文件。
BOM是一个特殊的Unicode字符,用于指示文本流的字节顺序。在UTF-8编码中,BOM是不必要的,因为UTF-8的字节顺序是固定的。
然而,一些程序(如Windows记事本)在保存UTF-8文件时会添加BOM。 当你使用utf-8-sig编码打开文件时,Python会自动删除文件开头的BOM(如果存在)。
这就是为什么在你的代码中,使用utf-8-sig可以解决KeyError: ‘列标题’问题的原因:因为实际的列名是’\ufeff列标题’,其中的\ufeff就是BOM。
如果你的文件可能包含BOM,那么使用utf-8-sig编码打开文件是一个好主意。否则,使用utf-8就足够了。
其他编码格式(例如gbk)如何处理BOM?
在Python中,gbk编码没有-sig的变体,所以不能使用gbk-sig来忽略BOM。对于gbk编码的文件,如果列名前有BOM,你可能需要在读取列名后手动删除它。
对于其他编码格式,如果它们有-sig的变体(如utf-8-sig),你可以使用这个变体来自动忽略BOM。
如果没有-sig的变体,你可能需要在读取列名后手动删除BOM。
Python读取列名手动删除BOM示例代码:
def read_csv_to_dict(filename):
with open(filename, 'r', errors='ignore', encoding='gbk') as f:
reader = csv.DictReader(f)
fieldnames = [name.lstrip('\ufeff') for name in reader.fieldnames] # 删除列名前的BOM
print(fieldnames)
data_dict = defaultdict(list)
for row in reader:
if row[fieldnames[4]] != '': # 使用处理过的列名
data_dict[row[fieldnames[0]]].append((row[fieldnames[1]], round(float(row[fieldnames[4]]))))
return data_dict
在上面的代码中,使用了lstrip(‘\ufeff’)来删除列名前的BOM。
不过你要注意的是,如果你需要在代码中继续添加处理文件的代码,后面的代码中你的列名要直接中使用处理过的列名(即fieldnames),而不是直接从row字典中获取列名。