2013-05-08 12 views
9

Sto usando il pacchetto difflib python. Non importa se imposto l'argomento isjunk, i rapporti calcolati sono gli stessi. La differenza di spazi non viene ignorata quando isjunk è lambda x: x == " "?ignora gli spazi quando si confrontano le stringhe in 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

potrebbe essere sbagliato, ma sarebbe 'a' e' B' sia essenzialmente diventano ' "abc"' se i loro spazi vengono ignorati da 'difflib'? – mdscruggs

+0

yes e restituisce '1.0' –

+0

2.7 docstring per SequenceMatcher:" .ratio() restituisce un float in [0, 1], misurando la "similarità" delle sequenze . Come regola generale, un .ratio () valore superiore a 0.6 significa che le sequenze sono corrispondenze ravvicinate " – mdscruggs

risposta

1

Si può vedere ciò che ritiene essere corrispondenti blocchi:

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

I primi due vi dico che corrisponde a "un b" a "un b" e "c" a "c". (L'ultimo è banale)

La domanda è perché "a b" può essere abbinato. Ho trovato la risposta a questo nel codice. Prima l'algoritmo trova un gruppo di blocchi corrispondenti chiamando ripetutamente find_longest_match. Cosa c'è di notevole di find_longest_match è che permette al personaggio spazzatura di esistere alle estremità della stringa:

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. 

Questo significa che prima si considera "a" e "b" di essere partite (permettendo il carattere spazio sulla fine di "a" e all'inizio di "b").

Quindi, la parte interessante: il codice esegue un ultimo controllo per vedere se uno qualsiasi dei blocchi è adiacente e li unisce se lo sono. Vedere questo commento nel codice:

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

Quindi, fondamentalmente è corrispondenti "a" e "b", quindi fondendo i due blocchi in "un b" e chiamando che una partita, nonostante il carattere di spazio essendo spazzatura.

0

Il numero di corrispondenze è uguale per entrambe le chiamate (3). È possibile controllare questo utilizzando:

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

(Essi sono in realtà la stessa a causa del modo in cui l'algoritmo di 'regola' per le partite adiacenti).

Poiché il rapporto dipende solo dalla lunghezza di queste corrispondenze e dalla lunghezza degli originali (junk inclusa), si ottengono le stesse razioni.

4

isjunk funziona in modo leggermente diverso da come si potrebbe pensare. In generale, isjunk identifica semplicemente uno o più caratteri che non influiscono sulla durata di una corrispondenza ma che sono ancora inclusi nel conteggio totale dei caratteri. Ad esempio, si consideri il seguente:

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

I primi quattro caratteri della seconda stringa ("abcd") sono tutti ignorabile, quindi la seconda stringa può essere paragonata alla prima stringa che inizia con lo spazio. A partire dallo spazio sia nella prima stringa che nella seconda stringa, quindi, sopra SequenceMatcher trova dieci caratteri corrispondenti (cinque in ogni stringa) e 4 caratteri non corrispondenti (i primi quattro caratteri ignorabili nella seconda stringa). Questo ti dà un rapporto di 10/14 (0.7142857142857143).

Nel tuo caso, quindi, la prima stringa "a b c" corrisponde alla seconda stringa agli indici 0, 1 e 2 (con valori "a b"). L'indice 3 della prima stringa (" ") non ha una corrispondenza ma viene ignorato in relazione alla durata della corrispondenza. Poiché lo spazio viene ignorato, l'indice 4 ("c") corrisponde all'indice 3 della seconda stringa. Quindi 8 dei tuoi 9 caratteri corrispondono, dandoti un rapporto di 0.88888888888888.

Si potrebbe desiderare di provare questo invece:

>>> c = a.replace(' ', '') 
>>> d = b.replace(' ', '') 
>>> difflib.SequenceMatcher(a=c, b=d).ratio() 
1.0 
Problemi correlati