如何String.Contains()C#中的模糊方式?

时间:2014-09-04 07:41:18

标签: c# fuzzy-search

我有一个我希望在过滤时搜索的人员列表。 每次用户输入搜索字符串时,都会应用过滤。

需要考虑两个挑战:

  1. 用户可以输入名称的一部分
  2. 用户可能错误输入
  3. 通过搜索子串,可以简单地解决第一个问题。 String.Contains()。第二个可以通过使用模糊实现(例如https://fuzzystring.codeplex.com

    来解决

    但我不知道如何同时掌握这两项挑战。

    例如:我想在进入其中一个时找到“Martin Fowler博士”的人:

    • “马丁”
    • “Fawler”
    • “Marten Fauler”

    我想我需要编写一个“FuzzyContains()”逻辑,它可以满足我的需求并具有可接受的性能。任何建议如何开始?

7 个答案:

答案 0 :(得分:4)

似乎是Levenshtein距离算法(one of the dozens C# implementations)的工作。

您为此算法提供两个字符串(用户输入的字符串和列表中的一个字符串)。然后计算从第一个字符串到第二个字符串必须替换,添加或删除的字符数。然后,您可以从列表中获取距离小于或等于三的所有元素(例如),以找到简单的拼写错误。

如果你有这种方法,你可以这样使用它:

var userInput = textInput.Text.ToLower();
var matchingEmployees = EmployeeList.Where(x => x.Name.ToLower().Contains(userInput)
                                                || LevenshteinDistance.Compute(x.Name.ToLower(), userInput) <= 3)
                                    .ToList();

答案 1 :(得分:3)

我修改了建议Levenshtein距离算法的Oliver answer,这不是这里的最佳选择,因为当只输入部分名称时计算的距离很大。所以,我最终使用了真棒Longest Common Subsequence algorithm实施的FuzzyString Lib

const int TOLERANCE = 1;
string userInput = textInput.Text.ToLower();
var matchingPeople = people.Where(p =>
{
     //Check Contains
     bool contains = p.Name.ToLower().Contains(userInput);
     if(contains) return true;

     //Check LongestCommonSubsequence
     bool subsequenceTolerated = p.Name.LongestCommonSubsequence(userInput).Length >= userInput.Length - TOLERANCE;

     return subsequenceTolerated;
}).ToList();

答案 2 :(得分:1)

我之前已经完成了这项工作,并开始使用wikipedia approximate string matching中列出的一些方法。当我完成后,我调整了我的算法的方式不是通用的,但在我的域中给了我更好的匹配。

如果你的整个字典在内存中并且不是太大,你可以简单地对字典中的每个成员应用匹配算法。如果您的字典很大,这可能会过度使用您的资源,您将需要更好的算法。您可能还想考虑使用数据库的全文搜索功能。

在我的例子中,我迭代了我的字典中的每个字符串,比较“匹配运行”,即2个点用于2个字符匹配,3个用于3个字符匹配,最多8个字符匹配。我跑了所有可能的对,三元组等等 - 对每个词典条目进行评分并选择最高得分的比赛。容忍错别字,词序等,但计算成本高 - 我的词典只有几千个短语,所以这对我来说效果很好。这是Dice's coefficient.

的修改版本

答案 3 :(得分:0)

你试过暴力吗?最简单的方法是将搜索字符串与从头开始的目标字符串的子字符串匹配,然后从所有匹配中获取最接近的匹配。

但是从性能视图来看这可能是不可接受的。

答案 4 :(得分:0)

也许你可以使用这个soundex实现:CodeProject soundex做的是比较两个字符串并以百分比计算“发音相似度”。 前一段时间我借助这个函数构建了一个搜索(PHP hasit内置)

答案 5 :(得分:0)

我前段时间有一个上学项目,我们有一个文本框,学生可以搜索每个员工,学生与学校有关。我们谈论的是几百人。我们在Core i3处理器上使用的简单Linq查询非常快。每次用户在文本框中键入内容时都会调用该查询。在TextChanged事件中,我们调用了一个如下所示的查询:

var resultData = EmployeeList.Where(x=>x.Name.ToLower().Contains(textInput.Text.ToLower())).ToList();

当然,这个逻辑只适用于你有#34;博士。 Martin Fowler&#34;在一个财产或成员。

答案 6 :(得分:0)

在像python这样的其他语言中,我们有很酷的文本处理内容,包括距离计算。 有一些算法,如 Levenshtein ,可以计算两个字符串之间的模糊距离。 我在C#(in here)中看到了一些实现,另一个模块是 difflib ,它可用in here。这些算法的输出是一个数字。越接近0越好。