
本文介绍使用 python 清洗含嵌入式换行符(crlf)的非标准 csv 文本文件的方法:精准识别每行逻辑记录(以 id 和日期结尾为标志),仅将行内换行替换为空格,保留真正的行边界,避免破坏字段结构。
本文介绍使用 python 清洗含嵌入式换行符(crlf)的非标准 csv 文本文件的方法:精准识别每行逻辑记录(以 id 和日期结尾为标志),仅将行内换行替换为空格,保留真正的行边界,避免破坏字段结构。
在实际数据集成场景中,常会遇到“伪 CSV”文件——表面用 ~ 分隔、无字段引号、且允许描述字段跨行(如示例中第 3 条记录的 description 包含多个 <cr></cr>)。这类文件无法被标准 csv 模块直接解析,因为 csv.reader 依赖换行符界定记录,而嵌入式换行会错误地拆分单条逻辑记录。
核心思路是:不按物理行分割,而按逻辑记录模式匹配。观察数据规律:每条有效记录均以数字 ID 开头、以 MM/DD/YY 格式日期结尾,中间字段数固定(由首行 header 决定)。据此可构造正则表达式锚定完整记录边界。
以下提供两种生产就绪方案,兼顾准确性与内存效率:
✅ 方案一:全量读取 + 正则批量提取(适合中小文件)
import re
with open('sample.txt', encoding='utf-8') as f_in:
header = f_in.readline().replace('~', ',') # 转换分隔符
content = f_in.read()
# 匹配逻辑行:ID + 任意三字段 + 日期(支持跨行)
pattern = r'\d+~[^~]*~[^~]*~[^~]*~\d{1,2}/\d{1,2}/\d{2}'
with open('cleaned.csv', 'w', encoding='utf-8') as f_out:
f_out.write(header)
for match in re.finditer(pattern, content, re.DOTALL):
# 将匹配到的整段内容中的换行符替换为空格,再补上行尾换行
cleaned_line = match.group(0).replace('\n', ' ').replace('\r', ' ').replace('~', ',')
f_out.write(cleaned_line + '\n')✅ 方案二:流式处理 + 缓冲区累积(推荐用于大文件)
import re
pattern = re.compile(r'^\d+~[^~]*~[^~]*~[^~]*~\d{1,2}/\d{1,2}/\d{2}$', re.MULTILINE)
with open('sample.txt', encoding='utf-8') as f_in, \
open('cleaned.csv', 'w', encoding='utf-8') as f_out:
header = f_in.readline().replace('~', ',')
f_out.write(header)
buffer = ''
for line in f_in:
buffer += line.rstrip('\r\n') + ' ' # 累积并统一处理换行
# 检查缓冲区是否已构成完整逻辑行(末尾含日期)
if re.search(r'\d{1,2}/\d{1,2}/\d{2}$', buffer.strip()):
# 清洗:去多余空格、替换分隔符、补换行
cleaned = re.sub(r'\s+', ' ', buffer.strip()).replace('~', ',')
f_out.write(cleaned + '\n')
buffer = ''
# 处理文件末尾可能残留的 buffer
if buffer.strip():
cleaned = re.sub(r'\s+', ' ', buffer.strip()).replace('~', ',')
f_out.write(cleaned + '\n')⚠️ 关键注意事项
-
分隔符一致性:示例中原始分隔符为
~,代码中统一转为,以兼容标准 CSV 工具;若需保留~,请删除.replace('~', ',')。 -
日期格式鲁棒性:正则中的
\d{1,2}/\d{1,2}/\d{2}假设日期为M/D/YY或MM/DD/YY。若存在YYYY年份或DD/MM/YYYY格式,需调整正则(如\d{1,2}/\d{1,2}/\d{2,4})。 -
字段内特殊字符:若
description中可能包含~或日期字符串(如“Meeting on 12/3/98”),上述正则会失效,此时应改用状态机解析或预处理标记嵌入式换行。 -
编码安全:务必显式指定
encoding='utf-8',避免 Windows/Linux 换行符(\r\nvs\n)导致匹配失败。
该方法本质是将“基于行”的解析升级为“基于模式”的记录重构,在无需外部库的前提下,可靠解决非标准文本数据的清洗痛点。


















