模糊搜索






4.95/5 (39投票s)
一个简单的模糊字符串搜索实现。
引言
本文描述了一个简单的模糊(字符串)搜索实现。它可以用于近似字符串匹配(有关更多信息,请参阅 http://en.wikipedia.org/wiki/Fuzzy_string_searching)。
存在其他近似字符串搜索算法(例如 Soundex),但这些算法的实现起来并不那么容易。本文中的算法易于实现,可用于以简单的方式使用近似字符串搜索的任务。
使用 List<string>
进行搜索,因此搜索数据库非常容易。
背景
该算法使用 Levenshtein 距离来确定词列表中字符串与要查找的单词的匹配程度。有关 Levenshtein 距离的信息可以在 http://en.wikipedia.org/wiki/Levenshtein_distance 上找到。
使用代码
以下示例将展示如何简单地使用该类。
static void Main(string[] args)
{
string word = "Code Project";
List<string> wordList = new List<string>
{
"Code Project",
"Code project",
"codeproject",
"Code Projekt",
"Kode Project",
"Other Project"
};
List<string> foundWords = FuzzySearch.Search(
word,
wordList,
0.70);
foundWords.ForEach(i => Console.WriteLine(i));
Console.ReadKey();
}
输出
Code Project
Code project
codeproject
Code Projekt
Kode Project
实现
展示了一个基本的方法。可以使用更优化的算法代替 Levenshtein 距离 - 但这里,为了清晰起见,提供了一个相当简单的实现。
Levenshtein 距离
为了计算 Levenshtein 距离,我使用以下算法
public static int LevenshteinDistance(string src, string dest)
{
int[,] d = new int[src.Length + 1, dest.Length + 1];
int i, j, cost;
char[] str1 = src.ToCharArray();
char[] str2 = dest.ToCharArray();
for (i = 0; i <= str1.Length; i++)
{
d[i, 0] = i;
}
for (j = 0; j <= str2.Length; j++)
{
d[0, j] = j;
}
for (i = 1; i <= str1.Length; i++)
{
for (j = 1; j <= str2.Length; j++)
{
if (str1[i - 1] == str2[j - 1])
cost = 0;
else
cost = 1;
d[i, j] =
Math.Min(
d[i - 1, j] + 1, // Deletion
Math.Min(
d[i, j - 1] + 1, // Insertion
d[i - 1, j - 1] + cost)); // Substitution
if ((i > 1) && (j > 1) && (str1[i - 1] ==
str2[j - 2]) && (str1[i - 2] == str2[j - 1]))
{
d[i, j] = Math.Min(d[i, j], d[i - 2, j - 2] + cost);
}
}
}
return d[str1.Length, str2.Length];
}
搜索过程
在搜索过程中,对于词列表中的每个单词,都计算 Levenshtein 距离,并以此距离计算一个分数。该分数代表字符串匹配的程度。输入参数 fuzzyness
确定字符串可以差异的大小。
public static List<string> Search(
string word,
List<string> wordList,
double fuzzyness)
{
List<string> foundWords = new List<string>();
foreach (string s in wordList)
{
// Calculate the Levenshtein-distance:
int levenshteinDistance =
LevenshteinDistance(word, s);
// Length of the longer string:
int length = Math.Max(word.Length, s.Length);
// Calculate the score:
double score = 1.0 - (double)levenshteinDistance / length;
// Match?
if (score > fuzzyness)
foundWords.Add(s);
}
return foundWords;
}
LINQ 变体
这段代码也可以用 LINQ 编写。
public static List<string> Search(
string word,
List<string> wordList,
double fuzzyness)
{
// Tests have prove that the !LINQ-variant is about 3 times
// faster!
List<string> foundWords =
(
from s in wordList
let levenshteinDistance = LevenshteinDistance(word, s)
let length = Math.Max(s.Length, word.Length)
let score = 1.0 - (double)levenshteinDistance / length
where score > fuzzyness
select s
).ToList();
return foundWords;
}
历史
- 2009 年 6 月 1日:初始发布。