文本清洗之前,先问清楚换行能不能丢
处理文本时,常见的一行代码是:
def normalize(text):
return " ".join(text.split())
它把词拆开,再用一个空格拼起来。连续空格、换行和制表符造成的形式差异,都会被压平。做关键词搜索时,这通常很方便;拿它判断两份文档是否一样,就需要先明确比较范围。
看两个固定示例:
old = "Alpha\nBeta"
new = "Alpha Beta"
print(old == new)
print(normalize(old) == normalize(new))
print(old.splitlines())
print(new.splitlines())
输出是:
False
True
['Alpha', 'Beta']
['Alpha Beta']
原始字符串不相同,归一化结果却相同。比较函数没有算错,而是输入转换已经抹掉了换行信息。下游再精确地比较字符串,也无法从两个相同的结果中还原这次变化。
这里最先要做的决定,是换行在业务里代表什么。
全文搜索可以主要关心词是否出现。配置文件、代码和分行说明可能还关心行边界。文档比较则可能需要区分段落、列表项和文本框。不能只因为它们最后都能表示成字符串,就使用同一种清洗规则。
一个直接的做法是保留不同用途的表示:
def representations(text):
return {
"raw": text,
"lines": text.splitlines(),
"search": " ".join(text.split()),
}
a = representations(old)
b = representations(new)
print(a["raw"] != b["raw"])
print(a["lines"] != b["lines"])
print(a["search"] == b["search"])
这三个结果可以同时为真:原文有变化,行结构有变化,搜索表示没有变化。它们回答的是不同问题。
splitlines() 只是这个示例的演示工具,不能直接当成所有文档的段落解析器。它默认不保留行结束符,单纯比较它的结果,也无法覆盖每一种原文差异。处理 PPTX、HTML 等结构化格式时,应从格式本身读取段落、节点或文本框,再决定哪些边界参与比较。
验证清洗规则时,至少准备三组输入:完全相同的文本、仅改变分行的文本、真正修改一个词的文本。分别写清楚预期结果。这样能检查程序有没有把应该保留的差异提前清掉,也能发现检测逻辑是不是始终返回“相同”。
清洗规则可以简化数据,但简化掉的信息也应当是明确允许丢弃的信息。先确定用途,再选择表示,比事后追查一次漏报更容易。
参考:Python 官方文档,str.split、str.join、str.splitlines
- 点赞
- 收藏
- 关注作者
评论(0)