10

我正在使用 difflib python 包。无论我是否设置isjunk参数,计算的比率都是相同的。isjunkis 时不忽略空格的差异lambda x: x == " "吗?

In [193]: difflib.SequenceMatcher(isjunk=lambda x: x == " ", a="a b c", b="a bc").ratio()
Out[193]: 0.8888888888888888

In [194]: difflib.SequenceMatcher(a="a b c", b="a bc").ratio()
Out[194]: 0.8888888888888888
4

3 回答 3

5

isjunk工作方式与您想象的略有不同。通常,isjunk仅标识一个或多个不影响匹配长度但仍包含在总字符数中的字符。例如,考虑以下情况:

>>> SequenceMatcher(lambda x: x in "abcd", " abcd", "abcd abcd").ratio()
0.7142857142857143

第二个字符串 ( "abcd") 的前四个字符都可以忽略,因此可以将第二个字符串与以空格开头的第一个字符串进行比较。从第一个字符串和第二个字符串中的空格开始,然后,上面SequenceMatcher找到 10 个匹配字符(每个字符串中 5 个)和 4 个不匹配字符(第二个字符串中可忽略的前四个字符)。这为您提供了 10/14 (0.7142857142857143) 的比率。

那么,在您的情况下,第一个字符串"a b c"与索引 0、1 和 2 处的第二个字符串匹配(带有 values "a b")。第一个字符串 ( " ") 的索引 3 没有匹配,但在匹配长度方面被忽略。由于空格被忽略,索引 4 ( "c") 匹配第二个字符串的索引 3。因此,您的 9 个字符中有 8 个匹配,给您的比率为0.88888888888888.

你可能想试试这个:

>>> c = a.replace(' ', '')
>>> d = b.replace(' ', '')
>>> difflib.SequenceMatcher(a=c, b=d).ratio()
1.0
于 2013-05-08T12:11:41.973 回答
1

您可以看到它认为是匹配块:

>>> difflib.SequenceMatcher(isjunk=lambda x: x == " ", a="a b c", b="a bc").get_matching_blocks()
[Match(a=0, b=0, size=3), Match(a=4, b=3, size=1), Match(a=5, b=4, size=0)]

前两个告诉你它匹配“a b”到“a b”和“c”到“c”。(最后一个是微不足道的)

问题是为什么可以匹配“a b”。我在代码中找到了答案。首先,算法通过重复调用 find_longest_match 找到一堆匹配块。find_longest_match 值得注意的是它允许垃圾字符存在于字符串的末尾:

If isjunk is defined, first the longest matching block is
determined as above, but with the additional restriction that no
junk element appears in the block.  Then that block is extended as
far as possible by matching (only) junk elements on both sides.  So
the resulting block never matches on junk except as identical junk
happens to be adjacent to an "interesting" match.

这意味着首先它认为“a”和“b”是匹配的(允许在“a”末尾和“b”开头的空格字符)。

然后是有趣的部分:代码最后一次检查是否有任何块相邻,如果是则合并它们。请参阅代码中的此注释:

    # It's possible that we have adjacent equal blocks in the
    # matching_blocks list now.  Starting with 2.5, this code was added
    # to collapse them.

所以基本上它匹配“a”和“b”,然后将这两个块合并为“a b”并称之为匹配,尽管空格字符是垃圾。

于 2013-05-08T03:30:22.787 回答
0

两次调用的匹配数相同 (3)。您可以使用以下方法进行检查:

print difflib.SequenceMatcher(isjunk=lambda x: x == " ", a="a b c", b="a bc").get_matching_blocks()
print difflib.SequenceMatcher(a="a b c", b="a bc").get_matching_blocks()

(它们实际上是相同的,因为算法为相邻匹配“调整”的方式)。

由于该比率仅取决于这些匹配的长度和原件的长度(包括垃圾),因此您得到相同的口粮。

于 2013-05-08T03:55:36.940 回答