String similarity

edit

Edit distance

// The number of insertions, deletions and substitutions that turn one word into the other
Assert.Equal(3, StringSearchUtilities.Levenshtein("kitten", "sitting"));

// With a maximum distance, the computation stops early and returns maxDistance + 1
Assert.Equal(2, StringSearchUtilities.Levenshtein("kitten", "sitting", maxDistance: 1));

// Compare one word with many candidates
var commands = new[] { "build", "test", "publish" };
Assert.Equal([1, 4, 5], StringSearchUtilities.LevenshteinBatch("buid", commands));
  • Levenshtein returns the number of single-character insertions, deletions and substitutions needed to turn one string into the other. Use it to suggest the closest command or option when the user makes a typo.
  • With maxDistance, the computation stops as soon as the distance is known to be greater, and returns maxDistance + 1. Pass it when you only care about close matches.
  • LevenshteinBatch compares a word with many candidates, in parallel, and returns one distance per candidate. maxDegreeOfParallelism limits the number of threads (-1, the default, lets the runtime decide).

Hamming distance

// The number of positions at which two strings of the same length differ
Assert.Equal(3, StringSearchUtilities.Hamming("karolin", "kathrin"));

// The number of different bits of two integers
Assert.Equal(2u, StringSearchUtilities.Hamming(0b1010u, 0b0110u));

Hamming counts the positions where two sequences of the same length differ: strings, any sequences, or the bits of two uint values. Sequences of different lengths throw an ArgumentException.

Phonetic codes

// Names that sound alike get the same code
Assert.Equal("R163", StringSearchUtilities.SoundexEnglish("Robert"));
Assert.Equal("R163", StringSearchUtilities.SoundexEnglish("Rupert"));
Assert.Equal(StringSearchUtilities.Metaphone("Smith"), StringSearchUtilities.Metaphone("Smyth"));

Phonetic algorithms give the same code to words that sound alike, to find names despite spelling variations:

MethodAlgorithm
SoundexEnglishThe English Soundex
SoundexFrenchA Soundex adapted to French
Soundex2An improved French Soundex
MetaphoneMetaphone, for English
SoundexA Soundex with your own table of letter codes and replacements

Store the code next to the name, and search by code.

Short names

ShortName.Create computes short names that are unique within a collection, for instance to name columns or files with a length limit:

// Create short names for a collection
var names = new[] { "CustomerName", "CustomerNumber", "CustomerAddress" };
var shortNames = ShortName.Create(names, maxLength: 5, StringComparer.OrdinalIgnoreCase);
Assert.Equal("Custo", shortNames["CustomerName"]);
Assert.Equal("Custm", shortNames["CustomerNumber"]);
Assert.Equal("Custe", shortNames["CustomerAddress"]);

The other overloads create one short name that does not collide with a set of existing short names, and return null when no unique short name fits in the maximum length.