String matching and fuzzy search
Edit distances with the dynamic-programming table filled cell by cell (Levenshtein, OSA vs true Damerau, LCS, Hamming), Jaro–Winkler, Levenshtein automata as Lucene's FuzzyQuery builds them and walks the term dictionary, Soundex, Metaphone, Double Metaphone and NYSIIS, pg_trgm trigram similarity, and a Norvig spelling corrector.
Added
How to use it
How search engines and databases decide that two strings are "close": the distances, the
automata Lucene builds so a fuzzy query never has to compare against every term, the phonetic
codes record-linkage systems use for names, PostgreSQL’s trigrams and a classic spelling
corrector. Everything runs in this page. ⛶ Full screen (or f) gives the tables and the
automaton diagram the whole window; Escape leaves.
How to use it
Edit distance. Type two strings (up to 40 characters each). The tiles give every distance at
once; tap one to see its table. The table is shown complete. Restart empties it, and Next,
Back and Play fill it one cell at a time. The current cell is solid, the cells it is computed
from are outlined (the winning one solid orange), and the line below spells out the minimum.
Once it is full, the traceback path is green and the alignment is written out: a, the operation
(| match, · substitution, ins, del, ⇄ transposition), then b.
-
Levenshtein: insert, delete or substitute, 1 each.
-
OSA (optimal string alignment, "restricted Damerau"): also swaps two adjacent letters for 1, but never edits a substring twice. That makes CA → ABC cost 3, although CA → AC → ABC costs 2, so OSA breaks the triangle inequality. Lucene counts this when
transpositionsis true. -
Damerau: the true Damerau–Levenshtein distance (Lowrance and Wagner, 1975). Letters may be inserted between a swapped pair, so CA → ABC costs 2. It is a metric.
-
LCS (longest common subsequence): only insertions and deletions; diff tools use it.
-
Substring: the longest common contiguous run.
-
Hamming: positions that differ, for equal lengths.
Jaro–Winkler. Matched letters (equal, at most ⌊max/2⌋ − 1 apart, which is the shaded band) are ticked. The tool counts transpositions and works the formula through. Winkler’s boost ℓ·p·(1 − J) uses the common prefix (ℓ ≤ 4, p = 0.1), and only when J is above the boost threshold (0.7, as Winkler and Lucene apply it; set 0 to boost always).
Levenshtein automata. Enter a term, the maximum edits (0–2, as in Lucene’s FuzzyQuery and
Elasticsearch’s fuzziness), the prefix length that must match exactly and whether a
transposition counts as one edit. The tool builds the nondeterministic automaton whose states
(i, e) mean "i letters of the term read, e edits used". It then determinises it by subset
construction over the term’s letters plus * (any other letter) and minimises it. The tiles
count the NFA, subset and minimal DFA states.
-
The diagram lays states out by distance from the start. Accepting states are double circles and edge labels list letters (
¬abmeans any letter but a and b). Tap a state to list the (i, e) pairs it stands for. Fit scales the drawing to the box; 100% draws it full size with scrolling. Transition table lists the same automaton as rows. -
Run a word through it: the path lights up. The tool says where the word is rejected and checks the answer against the distance computed by dynamic programming.
-
Against a term dictionary: the automaton walks a trie of the built-in 8,000-word list (or your own terms) depth-first in sorted order. That is the idea behind Lucene’s
Terms.intersect: a branch is abandoned the moment no state is left. The tool counts how much of the trie was visited and compares the matches with a brute-force distance check of every term (they always agree). The walk itself is listed underneath.
Phonetic. Paste names (commas or new lines). Each gets American Soundex, Metaphone, Double Metaphone (primary / secondary) and NYSIIS, and names that share a code are grouped. Tap a row for a letter-by-letter Soundex trace.
Trigrams. PostgreSQL’s pg_trgm on two texts: show_trgm for each (shared trigrams green),
similarity, word_similarity and strict_word_similarity with the working. Below it are
plain character n-gram Jaccard, Dice and cosine scores for n = 2–4. Run the real thing in the
Postgres lab.
Spelling. Peter Norvig’s corrector: if the word is known, keep it. Otherwise take the most frequent known word one edit away (deletion, swap, replacement or insertion), then two edits away. The tool shows how many candidate strings that generates and the winners with their probabilities. A text box corrects a whole sentence word by word.
Sources and reference values
The tests check every algorithm against published values:
-
Levenshtein, "Binary codes capable of correcting deletions, insertions and reversals" (1966): kitten → sitting = 3. Damerau (1964), and Lowrance and Wagner, "An extension of the string-to-string correction problem", JACM 1975: CA → ABC is 2 for the true distance and 3 for OSA.
-
Jaro (1989) and Winkler (1990), as tabulated in the Wikipedia article: MARTHA/MARHTA 0.944 / 0.961, DWAYNE/DUANE 0.822 / 0.840, DIXON/DICKSONX 0.767 / 0.813.
-
K. Schulz and S. Mihov, "Fast string correction with Levenshtein automata", IJDAR 2002, and Lucene’s
LevenshteinAutomataandFuzzyQuery(maxEdits ≤ 2, prefixLength, transpositions true by default). The tests check the automaton against brute-force distances on the whole word list and on thousands of random strings. Elasticsearch’s fuzziness AUTO means 0 edits below 3 characters, 1 for 3–5 and 2 above. -
American Soundex as the US National Archives defines it: Robert and Rupert R163, Rubin R150, Ashcraft and Ashcroft A261 (H and W do not separate), Tymczak T522, Pfister P236 (a letter coded like the first letter is not repeated), Honeyman H555.
-
Metaphone: Lawrence Philips, "Hanging on the Metaphone", Computer Language 7(12), 1990. This page follows the rule order of Apache Commons Codec’s
Metaphone(the tests use values from its test suite, such as TESTING → TSTN and SCHEDULE → SKTL), with Philips' CH → X throughout. Metaphone implementations differ in small ways. -
Double Metaphone: Lawrence Philips, "The Double Metaphone search algorithm", _C/C Users Journal_, June 2000. This is a port of his C reference via the Python
metaphonepackage. It matches that package on over a hundred names, except Hugh, where the Python port has a known slip and this page follows the C++. Smith → SM0 / XMT and Schmidt → XMT / SMT. -
NYSIIS: R. L. Taft, "Name Search Techniques", New York State Identification and Intelligence System, 1970, in the commonly published form. It matches the
jellyfishlibrary. Taft truncated codes to 6 characters (an option here). -
pg_trgm:
show_trgm('word')= {" w"," wo","ord","rd ","wor"}; for 'word' against 'two words', similarity 0.363636, word_similarity 0.8 and strict_word_similarity 0.571429. -
Peter Norvig, How to write a spelling corrector. The word counts are the 8,000 most frequent words of his
big.txt. Tests: speling → spelling, korrectud → corrected, bycycle → bicycle, inconvient → inconvenient, arrainged → arranged, peotry → poetry, peotryy → poetry.edits1('somthing')has 442 strings.
Limits
-
Edit-distance strings are capped at 40 characters. Costs are all 1 (no weighted or keyboard-distance costs).
-
Automaton terms are capped at 16 letters and edits at 2, like Lucene. The page determinises generically instead of using Lucene’s precomputed parametric tables, so the state counts are those of the minimal DFA, not of Lucene’s internal representation. Letters are compared exactly (no case folding), and a character is one Unicode code point.
-
The phonetic codes are for English names: accents are stripped and non-letters are ignored, and other languages need their own rules (Cologne phonetics, Beider–Morse).
-
The spelling corrector knows 8,000 words. Norvig’s full list (about 30,000) corrects more, and rarer correct words may be "corrected" here. It ignores context.
-
Trigram similarity follows pg_trgm’s rules for letters and digits. PostgreSQL’s handling of some non-ASCII characters depends on its locale.
Related: Postgres lab: full-text and trigram search, Diff (LCS on lines), Regex tester, Text tools and Unicode inspector.
Linking to an example
A link opens the tool with the given settings: /tools/fuzzy-match/?<parameters>#<tab>, where the tab
is edit, jaro, automaton, phonetic, trigram or spell. Share link (top right) builds
one from whatever is on screen.
| Parameter | Meaning | Example |
|---|---|---|
|
a preset (list below); other parameters in the same link override it |
|
|
the two strings on the Edit distance tab |
|
|
|
|
|
the two strings on the Jaro–Winkler tab |
|
|
Winkler’s prefix scale (≤ 0.25) |
|
|
boost threshold (0 = always boost) |
|
|
the fuzzy term |
|
|
max edits, 0–2 |
|
|
prefix length that must match exactly |
|
|
transpositions count as one edit ( |
|
|
word to run through the automaton |
|
|
|
|
|
your own term dictionary, words separated by commas |
|
|
names for the Phonetic tab, comma separated |
|
|
the two texts on the Trigrams tab |
|
|
n for the n-gram scores (2–4) |
|
|
the word to correct |
|
|
the sentence to correct |
|
Presets for example=:
| Name | Tab | Shows |
|---|---|---|
|
edit |
kitten → sitting: Levenshtein 3 (open) |
|
edit |
CA → ABC by true Damerau–Levenshtein: 2 (open) |
|
edit |
CA → ABC by OSA: 3 (open) |
|
edit |
LCS of AGGTAB and GXTXAYB: GTAB (open) |
|
edit |
karolin vs kathrin: 3 (open) |
|
jaro |
MARTHA / MARHTA: 0.944 / 0.961 (open) |
|
jaro |
DIXON / DICKSONX: 0.767 / 0.813 (open) |
|
automaton |
brown~1 against the word list, probing the typo “borwn” (open) |
|
automaton |
“search”~2 with prefix length 2, as a transition table (open) |
|
phonetic |
The National Archives’ Soundex examples (open) |
|
phonetic |
Smith and Schmidt share XMT in Double Metaphone (open) |
|
trigram |
similarity('word', 'two words') = 0.363636 (open) |
|
spell |
korrectud → corrected and a sentence (open) |
For example, ?term=elasticsearch&edits=2&prefix=1&probe=elasticserch#automaton
builds the automaton Elasticsearch’s fuzziness AUTO would use for a 13-letter term.
Feedback is a gift. Something to improve, a feature to add, or a bug? Tell me.
Runs entirely in your browser; nothing you type leaves this page.