2013-05-08 3 views
9

Я использую пакет python difflib. Независимо от того, установлен ли параметр isjunk, вычисленные коэффициенты совпадают. Разница между пробелами игнорируется, когда isjunk is lambda x: x == " "?игнорировать пробелы при сравнении строк в python

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 
+0

Может быть неправильно, но будет 'a' и' b' как по существу, становится '«а»', если их пробела игнорируются 'difflib'? – mdscruggs

+0

yes и он вернет '1.0' –

+0

2.7 docstring для SequenceMatcher:« .ratio() возвращает float в [0, 1], измеряя «подобие» последовательностей . Как правило, a .ratio () значение выше 0,6 означает, что последовательности являются близкими совпадениями " – mdscruggs

ответ

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» можно подобрать. Я нашел ответ на это в коде. Сначала алгоритм находит кучу соответствующих блоков, многократно называя 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»).

Затем, интересная часть: код делает последний чек, чтобы увидеть, смещен ли какой-либо из блоков, и объединяет их, если они есть. Смотрите этот комментарий в коде:

# 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. 

Так в основном это соответствие «а» и «б», то объединение этих двух блоков в «б» и называя, что матч, несмотря на символ пробела является нежелательной.

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() 

(они на самом деле то же самое из-за тем, как алгоритм «подстраивается» для соседних матчей).

Поскольку отношение зависит только от длины этих совпадений и длины оригиналов (включая нежелательные), вы получаете одинаковые пайки.

4

isjunk работает немного иначе, чем вы думаете. В общем случае isjunk просто идентифицирует один или несколько символов, которые не влияют на длину совпадения, но которые все еще включены в общий счетчик символов. Например, рассмотрим следующее:

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

Первые четыре символа второй строки ("abcd") все игнорируемые, так что вторая строка может быть по сравнению с первой строки, начиная с пространством. Начиная с места как в первой строке, так и во второй строке, то выше SequenceMatcher находит десять совпадающих символов (по пять в каждой строке) и 4 несоответствующих символа (игнорируемые первые четыре символа во второй строке). Это дает вам соотношение 10/14 (0.7142857142857143).

В вашем случае первая строка "a b c" соответствует второй строке индексов 0, 1 и 2 (со значениями "a b"). Индекс 3 первой строки (" ") не имеет соответствия, но игнорируется относительно длины совпадения. Так как пространство игнорируется, индекс 4 ("c") соответствует индексу 3 второй строки. Таким образом, 8 из 9 символов совпадают, что дает вам отношение 0.88888888888888.

Вы могли бы хотеть попробовать это вместо:

>>> c = a.replace(' ', '') 
>>> d = b.replace(' ', '') 
>>> difflib.SequenceMatcher(a=c, b=d).ratio() 
1.0 
Смежные вопросы