如何用Python 3解析包含嵌入换行符的CSV文件?
处理含单元格内换行的CSV文件解决方案
这个问题确实挺头疼的,尤其是从Excel/LibreOffice导出CSV时,单元格里的换行会变成字面的换行符,很容易让Python标准csv模块误判行边界。不过别慌,有几个实用的办法能解决:
方案1:正确配置标准csv模块参数
其实标准库不是不能处理,只是需要把参数配置对!因为办公软件导出的CSV通常会把带换行、逗号这类特殊字符的单元格用双引号括起来,只要告诉csv.reader识别这种引号包裹的内容,它就不会把里面的换行当成行结束。
试试这段代码:
import csv # 注意要设置newline='',这是csv模块文档推荐的写法,避免自动转换换行符 with open('your_data.csv', 'r', newline='', encoding='utf-8') as f: # quotechar指定引号类型,quoting设置为QUOTE_ALL表示所有被引号包裹的内容都作为单元格 reader = csv.reader(f, quotechar='"', quoting=csv.QUOTE_ALL) for row in reader: print(row)
如果你的CSV里只有部分单元格被引号包裹,也可以把quoting改成csv.QUOTE_MINIMAL,它会自动识别包含特殊字符的单元格。
方案2:用Pandas一键解决
如果项目里已经在用Pandas,那这事就更简单了——pd.read_csv默认就能正确解析带单元格内换行的CSV,完全不用手动调参数:
import pandas as pd df = pd.read_csv('your_data.csv') # 查看数据,单元格内的换行会被保留在对应字段里 print(df)
Pandas在处理这类CSV时会自动识别引号包裹的内容,把里面的换行当成单元格的一部分,非常省心,适合处理大型数据集。
方案3:手动解析(适合底层需求)
要是你不想依赖第三方库,也可以自己写逻辑来处理核心问题:判断当前是否处于引号包裹的状态,如果是,就把后续的行拼接到当前单元格里,直到遇到闭合的引号。
给你个参考实现:
def parse_csv_with_internal_newlines(file_path): rows = [] current_row = [] in_quotes = False current_cell = [] with open(file_path, 'r', encoding='utf-8') as f: for line in f: # 先去掉行尾的换行符,单元格内的换行后面再加回来 stripped_line = line.rstrip('\r\n') idx = 0 while idx < len(stripped_line): char = stripped_line[idx] if char == '"': # 切换引号状态 in_quotes = not in_quotes idx += 1 elif char == ',' and not in_quotes: # 遇到分隔符且不在引号内,结束当前单元格 current_row.append(''.join(current_cell)) current_cell = [] idx += 1 else: current_cell.append(char) idx += 1 # 处理完当前行后,判断是否还在引号里 if not in_quotes: # 行结束,把最后一个单元格加入行,再把行加入结果 current_row.append(''.join(current_cell)) rows.append(current_row) current_row = [] current_cell = [] else: # 还在引号内,说明当前行没结束,给单元格加个换行 current_cell.append('\n') # 处理最后可能剩余的未完成行 if current_row or current_cell: current_row.append(''.join(current_cell)) rows.append(current_row) return rows # 使用示例 parsed_data = parse_csv_with_internal_newlines('your_data.csv') for row in parsed_data: print(row)
这个方法比较底层,适合需要自定义解析逻辑的场景,但日常用的话还是前两种更高效。
补充一句:文档里说的“读取器被硬编码为识别'\r'或'\n'作为行尾,忽略lineterminator”,其实是指它会自动判断行结束符,但引号包裹范围内的换行是不会被当作行结束的——只要配置对quotechar和quoting参数,标准库完全能处理这种情况~
内容的提问来源于stack exchange,提问作者jpp1
相关产品推荐
相关产品推荐

