3

我正在阅读 Python 的diffllib的文档。根据每个文档,Differ delta 给出了一个序列

Code    Meaning
'- '    line unique to sequence 1
'+ '    line unique to sequence 2
'  '    line common to both sequences
'? '    line not present in either input sequence 

但是“更改”操作呢?如何获得类似于 Perl 的 sdiff中结果的“c”指令?

4

3 回答 3

2

看这个脚本。

sdiff.py@饥饿蛇网

http://hungrysnake.net/doc/software__sdiff_py.html

Perl 的 sdiff(Algorithm::Diff) 不考虑“匹配率”,但 python 的 sdiff.py 考虑一下。=)

我有 2 个文本文件。

$ cat text1.txt
aaaaaa
bbbbbb
cccccc
dddddd
eeeeee
ffffff

$ cat text2.txt
aaaaaa
bbbbbb
xxxxxxx
ccccccy
zzzzzzz
eeeeee
ffffff

我通过 sdiff 命令或 Perl 的 sdiff(Algorithm::Diff) 得到了并排差异。

$ sdiff text1.txt text2.txt
aaaaaa          aaaaaa
bbbbbb          bbbbbb
cccccc      |   xxxxxxx
dddddd      |   ccccccy
            >   zzzzzzz
eeeeee          eeeeee
ffffff          ffffff

Sdiff 不要考虑“匹配率” =(

我通过 sdiff.py 得到它

$ sdiff.py text1.txt text2.txt
--- text1.txt (utf-8)
+++ text2.txt (utf-8)
 1|aaaaaa             1|aaaaaa
 2|bbbbbb             2|bbbbbb
  |            >      3|xxxxxxx
 3|cccccc      |      4|ccccccy
 4|dddddd      <       |
  |            >      5|zzzzzzz
 5|eeeeee             6|eeeeee
 6|ffffff             7|ffffff

[     ]      |      + 
[ <-  ]     3|cccccc  
[  -> ]     4|ccccccy 

Sdiff.py 考虑“匹配率”=)

我想要 sdiff.py 的结果。你不是吗?

于 2013-12-15T04:18:20.000 回答
1

difflib中没有直接c类似的代码来显示更改的行,就像您谈到的 Perl 的 sdiff 中那样。但是你可以很容易地做一个。在 difflib 的 delta 中,“更改的行”也有'- ',但与实际删除的行相比,delta 中的下一行带有 标记,'? '表示 delta 的前一个索引中的行是“更改”的,而不是删除的。这条线在 delta 中的另一个目的是它充当“指南”,以了解更改在哪里。

因此,如果 delta 中的一行被标记为'- ',则根据 delta 的接下来几行,有四种不同的情况:

案例1:通过插入一些字符修改的行

- The good bad
+ The good the bad
?          ++++

案例2:通过删除一些字符来修改行

- The good the bad
?          ----
+ The good bad

情况 3:通过删除和插入和/或替换某些字符来修改行:

- The good the bad and ugly
?      ^^ ----
+ The g00d bad and the ugly
?      ^^          ++++

案例4:行被删除

- The good the bad and the ugly
+ Our ratio is less than 0.75!

如您所见,带有标记的行'? '准确显示了在何处进行了何种类型的修改。

请注意,如果ratio()正在比较的两行之间的值小于 0.75,则 difflib 认为删除了一行。这是我通过一些测试发现的值。

因此,要推断一条线已更改,您可以这样做。这将返回带有代码“c”标记的更改行和标记为“u”的未更改行的差异,就像在 Perl 的 sdiff 中一样:

def sdiffer(s1, s2):
    differ = difflib.Differ()
    diffs = list(differ.compare(s1, s2))

    i = 0
    sdiffs = []
    length = len(diffs)
    while i < length:
        line = diffs[i][2:]
        if diffs[i].startswith('  '):
            sdiffs.append(('u', line))

        elif diffs[i].startswith('+ '):
            sdiffs.append(('+', line))

        elif diffs[i].startswith('- '):
            if i+1 < length and diffs[i+1].startswith('? '): # then diffs[i+2] starts with ('+ '), obviously
                sdiffs.append(('c', line))
                i += 3 if i + 3 < length and diffs[i + 3].startswith('? ') else 2

            elif diffs[i+1].startswith('+ ') and i+2<length and diffs[i+2].startswith('? '):
                sdiffs.append(('c', line))
                i += 2
            else:
                sdiffs.append(('-', line))
        i += 1
    return sdiffs

希望能帮助到你。

PS这是一个老问题,所以我不确定我的努力会得到多大的回报。:-(我忍不住回答了这个问题,因为我最近一直在使用 difflib。

于 2016-02-10T16:32:29.133 回答
0

我不太了解 Perl 的“更改”操作是什么。如果它类似于 PHP DIFF 输出,我用这段代码解决了我的问题:

def sdiffer(s1, s2):
    differ = difflib.Differ()
    diffs = list(differ.compare(s1, s2))

    i = 0
    sdiffs = []
    length = len(diffs)
    sequence = 0
    while i < length:
        line = diffs[i][2:]
        if diffs[i].startswith('  '):
            sequence +=1
            sdiffs.append((sequence,'u', line))

        elif diffs[i].startswith('+ '):
            sequence +=1
            sdiffs.append((sequence,'+', line))

        elif diffs[i].startswith('- '):
            sequence +=1
            sdiffs.append((sequence,'-',diffs[i][2:]))
            if i+1 < length and diffs[i+1].startswith('? '):
                if diffs[i+3].startswith('?') and i+3 < length : # case 2
                    sequence +=1
                    sdiffs.append((sequence,'+',diffs[i+2][2:]))
                    i+=3
                elif diffs[i+2].startswith('?') and i+2 < length: # case 3
                    sequence +=1
                    sdiffs.append((sequence,'+',diffs[i+2][2:]))
                    i+=2
            elif diffs[i+1].startswith('+ ') and i+2<length and diffs[i+2].startswith('? '): # case 1
                sequence +=1
                sdiffs.append((sequence,'+', diffs[i+1][2:]))
                i += 2
            else: # the line is deleted and inserted new line # case 4
                sequence +=1
                sdiffs.append((sequence,'+', diffs[i+1][2:]))
                i+=1   
        i += 1
    return sdiffs

感谢@Sнаđошƒаӽ 您的代码。

于 2016-12-03T23:52:51.223 回答