Chris Collins

Tools · search

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 transpositions is 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 (¬ab means 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 LevenshteinAutomata and FuzzyQuery (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 metaphone package. 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 jellyfish library. 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.

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

example

a preset (list below); other parameters in the same link override it

osa-vs-damerau

a, b

the two strings on the Edit distance tab

kitten, sitting

algo

lev, osa, dam, lcs, lcsub or ham

dam

s1, s2

the two strings on the Jaro–Winkler tab

MARTHA

p

Winkler’s prefix scale (≤ 0.25)

0.1

thr

boost threshold (0 = always boost)

0.7

term

the fuzzy term

brown

edits

max edits, 0–2

1

prefix

prefix length that must match exactly

2

tr

transpositions count as one edit (true/false)

true

probe

word to run through the automaton

borwn

view

graph or table

table

dict

your own term dictionary, words separated by commas

apple,apply,ample

names

names for the Phonetic tab, comma separated

Smith,Schmidt

t1, t2

the two texts on the Trigrams tab

word, two words

gram

n for the n-gram scores (2–4)

3

w

the word to correct

speling

text

the sentence to correct

I cant spel

Presets for example=:

Name Tab Shows

kitten-sitting

edit

kitten → sitting: Levenshtein 3 (open)

osa-vs-damerau

edit

CA → ABC by true Damerau–Levenshtein: 2 (open)

osa-ca-abc

edit

CA → ABC by OSA: 3 (open)

lcs

edit

LCS of AGGTAB and GXTXAYB: GTAB (open)

hamming

edit

karolin vs kathrin: 3 (open)

martha

jaro

MARTHA / MARHTA: 0.944 / 0.961 (open)

dixon

jaro

DIXON / DICKSONX: 0.767 / 0.813 (open)

lucene-fuzzy

automaton

brown~1 against the word list, probing the typo “borwn” (open)

fuzzy-2-prefix

automaton

“search”~2 with prefix length 2, as a transition table (open)

soundex-nara

phonetic

The National Archives’ Soundex examples (open)

smith-schmidt

phonetic

Smith and Schmidt share XMT in Double Metaphone (open)

pg-trgm

trigram

similarity('word', 'two words') = 0.363636 (open)

norvig

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.

Runs entirely in your browser; nothing you type leaves this page.