段落匹配 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的主要内容,如果未能解决你的问题,请参考以下文章

Python模糊匹配 | 刷英语六级段落匹配只需要3秒?

Python模糊匹配 | 刷英语六级段落匹配只需要3秒?

使用 sed/awk/grep 匹配段落并替换为新段落 [重复]

正则表达式:匹配文本段落中除特定短语外的所有内容

使用Solr从段落中进行短语匹配

正则表达式匹配换行