2013-05-08 19 views
9

Używam pakietu pythów difflib. Bez względu na to, czy ustawiłem argument isjunk, obliczone współczynniki są takie same. Czy różnica odstępów nie jest ignorowana, gdy isjunk jest lambda x: x == " "?ignoruj ​​spacje podczas porównywania ciągów w pythonie

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

może być źle, ale 'A' i' B' zarówno zasadniczo stać ' "abc"' jeżeli ich przestrzenie są ignorowane przez 'difflib'? – mdscruggs

+0

yes i to zwróci '1.0' –

+0

2.7 docstring dla SequenceMatcher:" .ratio() zwraca wartość zmiennoprzecinkową w [0, 1], mierząc "podobieństwo" sekwencji . Zgodnie z regułą, .ratio () wartość powyżej 0,6 oznacza, że ​​sekwencje są bliskimi odpowiednikami " – mdscruggs

Odpowiedz

1

Można zobaczyć to, co uważa za dopasowane bloki:

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

Pierwsze dwa powiedzieć, że mecze "a b" do "b" i "c" na "c". (Ostatni jest banalny)

Pytanie brzmi, dlaczego można dopasować "a b". Odpowiedź znalazłem w kodzie. Najpierw algorytm znajduje grupę dopasowanych bloków, wielokrotnie wywołując find_longest_match. Co godne uwagi o find_longest_match jest to, że pozwala postać śmieci istnieć na końcach łańcucha:

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. 

oznacza to, że pierwszy uzna „a” i „b” do bycia mecze (pozwalające na charakter miejsca na koniec "a" i na początku "b").

Następnie interesująca część: kod wykonuje jedną ostatnią kontrolę, aby zobaczyć, czy któryś z bloków sąsiaduje z nim i scala je, jeśli są. Zobacz ten komentarz w kodzie:

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

więc w zasadzie to dopasowanie „a” i „b”, a następnie łącząc te dwa bloki na „a b” i nazywając że mecz pomimo znak spacji jest śmieci.

0

Liczba dopasowań jest taka sama dla obu wywołań (3). Można to sprawdzić za pomocą:

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

(W rzeczywistości są one tak samo ze względu na sposób algorytm „reguluje” dla sąsiednich meczów).

Ponieważ stosunek zależy tylko od długości tych dopasowań i długości oryginałów (w tym śmieci), otrzymujesz te same racje.

4

działa nieco inaczej niż mogłoby się wydawać. Ogólnie rzecz biorąc, isjunk jedynie identyfikuje jeden lub więcej znaków, które nie wpływają na długość meczu, ale nadal są uwzględniane w całkowitej liczbie znaków. Na przykład, należy rozważyć następujące kwestie:

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

Pierwsze cztery znaki drugiego ciągu ("abcd") są wszystkie ignorable, więc drugi ciąg można porównać do pierwszego ciągu rozpoczynającego się z miejsca. Zaczynając od spacji zarówno w pierwszym ciągu, jak i drugim łańcuchu, powyższe SequenceMatcher znajduje dziesięć pasujących znaków (pięć w każdym ciągu znaków) i 4 niepasujące znaki (cztery pierwsze znaki w drugim ciągu). Daje to stosunek 10/14 (0.7142857142857143).

W twoim przypadku pierwszy ciąg "a b c" dopasowuje drugi ciąg w indeksach 0, 1 i 2 (z wartościami "a b"). Indeks 3 pierwszego ciągu znaków (" ") nie ma dopasowania, ale jest ignorowany pod względem długości dopasowania. Ponieważ spacja jest ignorowana, indeks 4 ("c") odpowiada indeksowi 3 drugiego ciągu. Tak więc 8 z 9 znaków pasuje, co daje stosunek 0.88888888888888.

Można spróbować to zamiast:

>>> c = a.replace(' ', '') 
>>> d = b.replace(' ', '') 
>>> difflib.SequenceMatcher(a=c, b=d).ratio() 
1.0 
Powiązane problemy