CSV文件作为一种通用的数据交换格式,在实际业务场景中经常被使用,但很多业务导出的CSV文件并不严格遵循RFC 4180标准,会出现字段多余引号、字段内容包含换行符却未正确转义的情况,使用常规的文件行读取方式无法正确解析这类文件。Python标准库的csv模块提供了完善的解析规则,能够优雅处理这些异常场景。

常规CSV读取的问题
如果直接使用open函数按行读取CSV文件,遇到字段内包含换行的情况会把一条数据拆分成多行,遇到多余引号也会导致分割错误。比如下面这样的CSV内容:
id,name,desc 1,"张三","这是一段 多行描述" 2,"李四","正常描述"
如果直接按行读取,会把第一条数据的两行当成两条记录,导致解析错误。
使用csv模块基础读取
csv模块的reader对象会自动处理引号包裹的字段,识别字段内的换行符,只要CSV文件的引号使用符合基本规则,就能正确解析。基础用法如下:
import csv
# 读取CSV文件,指定编码和分隔符
with open("test.csv", "r", encoding="utf-8") as f:
reader = csv.reader(f)
for row in reader:
print(row)
上述代码会正确输出第一条记录的desc字段为包含换行的完整内容,不会错误拆分记录。
处理多余引号的场景
如果CSV文件中存在未转义的多余引号,比如字段内容里本身包含双引号却没有用两个双引号转义,或者字段开头结尾多了多余的引号,可以通过自定义引号处理逻辑解决。比如处理字段内单个双引号的情况,可以先读取原始行,对引号做预处理再交给csv解析:
import csv
def clean_quotes(line):
# 简单处理字段内未转义的双引号,替换为两个双引号符合csv转义规则
# 注意此逻辑仅适用于简单场景,复杂场景需要调整
return line.replace('""', '"').replace('"', '""')
with open("test.csv", "r", encoding="utf-8") as f:
lines = f.readlines()
processed_lines = [clean_quotes(line) for line in lines]
# 使用csv.reader解析处理后的内容
reader = csv.reader(processed_lines)
for row in reader:
print(row)
自定义方言处理特殊格式
如果CSV文件的格式有特殊规则,比如使用单引号包裹字段,或者分隔符不是逗号,可以自定义csv方言来适配:
import csv
# 注册自定义方言,使用单引号作为引号字符,逗号作为分隔符
csv.register_dialect("custom_dialect",
quotechar="'",
delimiter=",",
escapechar="\",
doublequote=True,
skipinitialspace=True
)
with open("test.csv", "r", encoding="utf-8") as f:
reader = csv.reader(f, dialect="custom_dialect")
for row in reader:
print(row)
写入时正确处理引号和换行
如果需要把处理后的数据重新写入CSV,使用csv.writer可以自动处理字段内的引号和换行,不需要手动添加转义:
import csv
data = [
["id", "name", "desc"],
[1, "张三", "这是一段n多行描述"],
[2, "李四", "正常描述"带引号"]
]
with open("output.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
writer.writerows(data)
上述代码写入的文件会正确用引号包裹包含换行和引号的字段,符合CSV标准格式,后续读取时也不会出现解析错误。
注意事项
- 打开CSV文件时建议指定
newline="",避免不同系统下的换行符转换问题。 - 如果CSV文件编码不是utf-8,需要对应调整
encoding参数,比如gbk编码的文件使用encoding="gbk"。 - 预处理引号的逻辑需要根据实际文件格式调整,避免误处理正常内容。
- 对于格式极度混乱的CSV文件,可以先使用正则表达式做初步清洗,再交给csv模块解析。