2014-01-30 39 views
8

背景资料段匹配的Python

我有产生与docx模块word文档的Python脚本。这些文档是基于日志生成的,然后打印并存储为记录。但是,日志可以追溯编辑,因此需要修改文档记录,并且必须跟踪这些修订。我实际上并没有修改这些文档,而是生成了一个新的文档,它显示了日志中当前内容与即将在日志中的内容之间的区别(在修改后的文件被打印后日志被更新)。当修订时,我的脚本使用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是一种非常有效的代码,发现两个文本之间的差异。 Unfortuanly,它有点太有效率,因此与dune结果替换redundant

重新 逼债 蚂蚁 Ë

这是丑陋的,但其单个词的罚款。但是,如果整个段落被替换,结果将是完全不可读的。那不好。

此前我通过将所有文本合并为一个段落来解决这个问题,但这并不理想,因为它变得非常混乱,而且还很丑陋。


解决方案到目前为止

我有创建修改文档的功能。这个函数会得到建立这样的元组的列表:

[(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做段落匹配。但是,如果有更好的方法来避免这种完全不同的方法,那也很好。


需要注意以下几点:

  • 我运行的Python 2.7.6 32位的Windows 7 64位
  • 我做了一些改变,我的本地副本的docx(即通过添加格式罢工),所以如果你测试这个代码,你将不能够复制我在这方面正在做

在整个过程

描述(以粗体修订步骤):

1)用户打开Python脚本,并使用GUI将信息添加到一个叫做“状况报告”(CR)的事情

注意:完整的CR包含4个部分,全部由不同的人完成。但是每个部分都可以单独打印。所有4个部分 一起存储的日志

2)当用户完成时,信息将保存到日志(下文描述)中,然后打印为.docx文件

3)打印的文件被签名并存储

4)当用户想要修改部分CR时,打开GUI并编辑每个字段中的信息。我只关心这个问题中的几个字段,这些是多行文本控件(可能会导致多个段落)

5)一旦用户完成修订,代码会生成元组列表,我在“迄今为止的解决方案”一节中描述,并将其发送到生成修订文档的功能

6)修订文档创建,打印,签名并与原始文档一起存储部分该CR

7)日志被完全重写,包括修订后的信息


日志:

日志简直是一个巨大的dict存储上的所有CRS的所有信息。一般格式为

{"Unique ID Number": [list of CR info]} 

日志不存储过去的CR版本,因此当CR修订旧的信息被覆盖(这就是我们想要的系统)。正如我前面提到的,每次编辑日志时,整个事情都会被重写。要获取日志中的信息,我import它(因为它总是生活在同一目录中的脚本)

+1

你看过diff_match_patch具有的post-diff清理选项吗?假设您使用的是http://code.google.com/p/google-diff-match-patch/ - 看起来语义清理就是您要找的内容。 – tzaman

+0

我认为这些功能在差异时正常运行 – wnnmaw

+0

好吧,我现在看到我的原始答案不会帮助你太多,因为你没有区分.docx文件。我删除了这个答案。我会提供的唯一建议是考虑将日志的各种版本渲染为纯文本格式,然后您可以使用difflib。这样你就不必尝试重新发明一些非常棘手的代码。如果您尝试使用各种纯文本记录布局,则可能会发现其中一个diff,它可以很好地隔离这些更改。如果你需要使它变得更漂亮一些,你总是可以解析diff输出以将其输入到Word中。 – scanny

回答

1

尝试使用diff_match_patch @tzaman上面提到的diff_match_patch之后的差异化清理选项,特别是检查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, '.')] 

正如你可以看到,第一个差异是最佳的,但不可读的,而第二个DIF(清理后)究竟是你正在找。