Python csv 模块读写含换行与逗号的字段:别再用 split 手动解析
用 csv 模块读写含换行与逗号的字段
问题场景
CSV 看起来简单,但字段里一旦出现逗号或换行,用 line.split(',') 就会错位。
例如数据文件 input.csv 内容如下:
id,name,note
1,example,comma,line one
line two
这里第二行本意可能是 id 为 1,name 为 example,comma,note 为两行文本。但因为没有引号,解析器无法区分字段内的逗号和换行。按行读取再 split(','),note 会被拆成两行,example 和 comma 也会被拆成两列,列数不一致,行就错位了。
手动 split 的局限
line.split(',')无法区分字段分隔符和字段内容里的逗号。- 按行读取无法区分记录结束换行和字段内换行。
- 引号内的转义双引号,例如两个连续双引号表示一个双引号,也无法正确还原。
因此,只要数据可能包含逗号、换行、双引号,就应交给标准库 csv 解析,而不是自己写切分逻辑。
用 csv.reader 读
关键点:打开文件时传 newline='',让 csv 模块自己处理换行。
import csv
with open('input.csv', 'r', encoding='utf-8', newline='') as f:
reader = csv.reader(f)
for row in reader:
print(len(row), row)
reader 会正确处理带引号的字段:引号内的逗号保留在字段内,引号内的换行保留在字段内,两个连续双引号还原为一个双引号。
用 csv.writer 写
写入时不需要手动拼引号。csv.writer 会根据方言自动给需要转义的字段加引号。
import csv
rows = [
['id', 'name', 'note'],
[1, 'example,comma', '''line one
line two'''],
[2, 'plain', 'text'],
]
with open('output.csv', 'w', encoding='utf-8', newline='') as f:
writer = csv.writer(f)
writer.writerows(rows)
这里 note 字段中的换行会写成字段内的换行,example,comma 会因为含逗号而被双引号包裹。读取时可以还原成原来的字段。
最小可运行示例
将下面代码保存为 demo.py。代码先写入 output.csv,再读回并打印,便于观察字段是否保持完整。
import csv
def write_demo(path):
rows = [
['id', 'name', 'note'],
[1, 'example,comma', '''line one
line two'''],
[2, 'plain', 'text'],
]
with open(path, 'w', encoding='utf-8', newline='') as f:
writer = csv.writer(f)
writer.writerows(rows)
def read_demo(path):
with open(path, 'r', encoding='utf-8', newline='') as f:
reader = csv.reader(f)
for row in reader:
print(len(row), row)
if __name__ == '__main__':
write_demo('output.csv')
read_demo('output.csv')
运行方法:
python demo.py
输出中每行记录应有 3 个字段。第二行的 note 字段会是一个包含换行的字符串。注意 csv.reader 读出的字段都是字符串,数字 1 会变成 '1',需要业务层自行转换。
边界与限制
- 必须使用
newline='':这是官方文档推荐做法,避免在 Windows 等平台上出现多余空行或换行处理冲突。 - 编码要显式指定:
csv模块不负责编码。UTF-8 用encoding='utf-8';如果文件带 BOM,可尝试utf-8-sig。不要依赖系统默认编码。 - 方言不等于自动识别:默认是
excel方言,逗号分隔、双引号包裹。TSV 可以设置delimiter为制表符;其它引号规则可设置quotechar、quoting、escapechar。csv.Sniffer可以猜测方言,但只适合小样本,猜测可能失败。 - 字段不会自动去空白:
reader不会去掉字段两侧空格。需要时可用skipinitialspace=True,但不要无差别strip(),否则可能改变真实数据。 - 大文件逐行迭代:
for row in reader是流式读取,不要写list(reader)一次性载入,除非确认内存足够。 - 写入换行符:
writer默认使用 CRLF。如果交换环境要求 LF,可以显式设置lineterminator,但需确认接收方兼容。 - 公式注入与安全:
csv模块只负责格式,不负责安全。字段以等号、加号、减号、@ 开头时,导出给表格软件可能被当公式;需要自行加前缀或转义。 - 非字符串值:建议在写入前显式转换类型,避免依赖
writer的隐式字符串化行为,这会让数据含义更清晰。
小结
字段中可能含逗号、换行、双引号时,不要手动 split。用 csv.reader 和 csv.writer 读写,并注意 newline=''、显式编码和方言设置。这样能避免行错位,也能让数据在常见 CSV 解析器之间保持兼容。
- 点赞
- 收藏
- 关注作者
评论(0)