段落匹配 Python
Posted
技术标签:
【中文标题】段落匹配 Python【英文标题】:Paragraph Matching Python 【发布时间】:2014-01-30 20:34:53 【问题描述】:背景信息
我有一个 Python 脚本,它使用 docx
模块生成 word 文档。这些文档基于日志生成,然后打印并存储为记录。但是,日志可以追溯编辑,因此需要修改文档记录,并且必须跟踪这些修改。我实际上并没有修改文档,而是生成一个新文档,显示当前日志中的内容与日志中即将出现的内容之间的差异(打印修改后的文件后更新日志)。当发生修订时,我的脚本使用diff_match_patch
生成使用以下函数更改的标记:
def revFinder(str1,str2):
dmp = dmp_module.diff_match_patch()
diffs = dmp.diff_main(str1,str2)
paratext = []
for diff in diffs:
paratext.append((diff[1], '' if diff[0] == 0 else ('s' if diff[0] == -1 else 'b')))
return paratext
docx
可以将文本作为字符串,或者如果需要逐字格式化,则可以使用元组,因此[请参阅“注意事项”中的第二个项目符号]
[("Hello, ", ''), ("my name ", 'b'), ("is Brad", 's')]
生产
你好我的名字
是布拉德
问题
diff_match_patch
是一个非常有效的代码,可以找出两个文本之间的差异。不幸的是,它有点太高效了,所以用dune
替换redundant
会导致
redunante
这很难看,但对于单个单词来说很好。但是,如果整个段落被替换,结果将完全不可读。那不行。
之前我通过将所有文本折叠成一个段落来解决这个问题,但这并不理想,因为它变得非常混乱并且仍然非常难看。
目前的解决方案
我有一个创建修订文档的函数。这个函数被传递了一个这样设置的元组列表:
[(fieldName, original, revised)]
所以文档设置为
Orignial fieldName (With Markup)
result of revFinder diffing orignal and revised
Revised fieldName
revised
我假设为了解决问题,我需要在段落之间进行某种匹配,以确保我不会区分两个完全独立的段落。我还假设这种匹配将取决于是否添加或删除段落。这是我到目前为止的代码:
if len(item[1].split('\n')) + len(item[1].split('\n'))) == 2:
body.append(heading("Original (With Markup)".format(item[0]),2))
body.append(paragraph(revFinder(item[1],item[2])))
body.append(paragraph("",style="BodyTextKeep"))
body.append(heading("Revised ".format(item[0]),2))
body.append(paragraph(item[2]))
body.append(paragraph(""))
else:
diff = len(item[1].split('\n')) - len(item[1].split('\n'))
if diff == 0:
body.append(heading("Original (With Markup)".format(item[0]),2))
for orPara, revPara in zip(item[1].split('\n'),item[2].split('\n')):
body.append(paragraph(revFinder(orPara,revPara)))
body.append(paragraph("",style="BodyTextKeep"))
body.append(heading("Revised ".format(item[0]),2))
for para in item[2].split('\n'):
body.append(paragraph("".format(para)))
body.append(paragraph(""))
elif diff > 0:
#Removed paragraphs
elif diff < 0:
#Added paragraphs
到目前为止,我已经计划使用 difflib
之类的东西来进行段落匹配。但如果有更好的方法来避免这个问题,这是一种完全不同的方法,那也很好。
注意事项:
我在 Windows 7 64 位上运行 Python 2.7.6 32 位 我已经对我的本地副本docx
进行了一些更改(即通过格式添加删除线),因此如果您测试此代码,您将无法复制我在这方面所做的事情
整个过程的描述(修订步骤以粗体显示):
1) 用户打开 Python 脚本并使用 GUI 将信息添加到称为“条件报告”(CR)的事物中
注意:完整的 CR 包含 4 个部分,均由不同的人完成。但是每个部分都是单独打印的。 4个部分都是 一起存储在日志中
2) 用户完成后,信息会保存到日志中(如下所述),然后打印为.docx
文件
3) 打印的文档被签名并保存
4) 当用户想要修改CR的一部分时,打开GUI,编辑每个字段的信息。我只关心这个问题中的几个字段,那些是多行文本控件(可能导致多个段落)
5) 用户完成修订后,代码会生成我在“到目前为止的解决方案”部分中描述的元组列表,并将其发送到生成修订文档的函数
6) 修订文档与该部分 CR 的原始文档一起创建、打印、签名和存储
7)日志被完全重写以包含修改后的信息
日志:
日志只是一个巨大的dict
,它存储了所有CR 的所有信息。一般格式是
"Unique ID Number": [list of CR info]
日志不存储 CR 的过去版本,因此当 CR 被修改时,旧信息会被覆盖(这是我们想要的系统)。正如我之前提到的,每次编辑日志时,都会重写整个内容。为了获取日志中的信息,我import
它(因为它始终与脚本位于同一目录中)
【问题讨论】:
您是否查看过 diff_match_patch 具有的差异后清理选项?假设您使用的是 code.google.com/p/google-diff-match-patch -- 似乎语义清理就是您要寻找的内容。 我认为这些函数在 diff 时运行正常 好的,我现在看到我的原始答案对您没有太大帮助,因为您没有对 .docx 文件进行比较。我删除了那个答案。我要提供的唯一建议是考虑将各种版本的日志呈现为纯文本格式,然后您可以使用 difflib。这样您就不必尝试重新发明一些非常棘手的代码。如果您尝试使用各种纯文本记录布局,您可能会发现差异在隔离更改方面做得非常好。如果您需要让它更漂亮一点,您可以随时解析 diff 输出以将其导入 Word。 【参考方案1】:尝试使用上面提到的@tzaman diff_match_patch 的post-diff 清理选项,特别是检查diff_cleanupSemantic
函数,该函数旨在用于当差异输出旨在供人类阅读时使用。
清理选项不会自动运行,因为 diff_match_patch 提供了几个可供您选择的清理选项(取决于您的需要)。
这是一个例子:
import diff_match_patch
dmp = diff_match_patch.diff_match_patch()
diffs = dmp.diff_main('This is my original paragraph.', 'My paragraph is much better now.')
print diffs # pre-cleanup
dmp.diff_cleanupSemantic(diffs)
print diffs # post cleanup
输出:
[(-1, 'This is m'), (1, 'M'), (0, 'y'), (-1, ' original'), (0, ' paragraph'), (1, ' is much better now'), (0, '.')]
[(-1, 'This is my original paragraph'), (1, 'My paragraph is much better now'), (0, '.')]
如您所见,第一个差异是最佳的但不可读,而第二个差异(清理后)正是您要寻找的。p>
【讨论】:
【参考方案2】:考虑使用 git 来管理所有这些修订,请参阅GitPython 获取 python api,另请参阅 Git (or Hg) plugin for dealing with Microsoft Word and/or OpenOffice files 了解如何 xmldiff 并每行有一个元素
【讨论】:
感谢您的回答,但恐怕这行不通。我没有将信息存储在文档中,也没有对其进行编辑,因此 Git 不太适合。我应该在问题中澄清更多以上是关于段落匹配 Python的主要内容,如果未能解决你的问题,请参考以下文章