Un punto di partenza approssimativo per la ricerca di stringhe è quello del distanza di Levenshtein . Questo algoritmo conta il numero di modifiche a carattere singolo (inserisci, elimina e sostituisci) per cambiare una parola in un'altra.
Un esempio di questo è kitten
-> sitting
che ha una distanza di modifica di tre
- k itten -> s itten (sostituisce 's' per 'k')
- sitt e n -> sitt i n (sostituisci "i" con "e")
- sittin -> sittin g (aggiungi 'g' alla fine)
Ci sono variazioni su questo algoritmo, in particolare il distanza Damerau-Levenshtein che consente la trasposizione di due caratteri adiacenti ("hte" a "the" ha una distanza DL di 1 e una distanza di Levenshtein di 2) e quindi è spesso più appropriato per controllo ortografico. Esistono altre varianti per applicazioni in cui le lacune sono importanti (stringhe di DNA).
La distanza di Levenshtein è ben nota e non troppo difficile da trovare (una volta avevo motivo di cercarne un'implementazione come una funzione in oracolo : era molto più veloce che abbattere tutti i dati e quindi eseguire il lato del codice di query). Rosettacode ha una moltitudine (54) di implementazioni della distanza Levenshtein (nota che alcune lingue hanno questo come parte della libreria di stringhe da qualche parte - se stai facendo Java, guarda l' apache commons lang ). Wikibooks ha 31 implementazioni e uno sguardo veloce ai due non mostra lo stesso codice per la stessa lingua.
Il modo in cui funziona è che crea una matrice che corrisponde alla relazione tra le due stringhe:
.kitten
.0123456
s1123456
i2212345
t3321234
t4432123
i5543223
n6654332
g7765443
Il .
riga e la colonna indicano che è possibile raggiungere la stringa target inserendo "solo" ogni lettera da una stringa vuota. Questo non è il caso ideale, ma è lì per seminare l'algoritmo.
Se il valore è lo stesso di quello spot ('i' == 'i'), il valore è uguale al valore in diagonale verso sinistra. Se i due punti sono diversi ('s'! = 'K') il valore è il minimo di:
- diagonale verso l'alto e verso sinistra + 1 (una sostituzione)
- direttamente sopra + 1 (un inserimento)
- direttamente a sinistra + 1 (una cancellazione)
Il valore di ritorno della distanza di modifica è il valore in basso a destra della matrice.
Se segui da in basso a destra in alto a sinistra con il minimo, puoi vedere le modifiche fatte:
.kitten
.0. .
s.1 .
i 1 .
t 1 .
t 1.
i.....2
n 2
g......3
Si noti che questo è l'approccio piuttosto intensivo di memoria. Può essere ridotto nell'ambito della memoria non costruendo la matrice completa: tutto l'algoritmo a cui importa è un sottoinsieme dei dati e può essere ridotto da N*M
spazio a 2*max(N,M)
spazio semplicemente memorizzando la riga precedente (e ciò che è stato calcolato sull'attuale riga). Code Project mostra come eseguire questa operazione (con il codice C # da scaricare).