我需要比较2个字符串并计算它们的相似度,以过滤掉最相似字符串的列表。
EG。寻找“狗”将返回
EG。寻找“破解”将返回
我遇到过:
你知道更多的字符串相似度算法吗?
答案 0 :(得分:25)
Levenshtein距离是我推荐的算法。它计算将1个字符串更改为另一个字符串必须执行的最小操作数。变化越少意味着字符串越相似......
答案 1 :(得分:19)
似乎你需要某种模糊匹配。这是一组相似性度量http://www.dcs.shef.ac.uk/~sam/stringmetrics.html的java实现。以下是字符串度量http://www.cs.cmu.edu/~wcohen/postscript/ijcai-ws-2003.pdf的更详细说明,它取决于实现的模糊程度和速度。
答案 2 :(得分:9)
如果重点是性能,我会实现一个基于trie
结构的算法
(适用于在文本中查找单词或帮助更正单词,但在您的情况下,您可以快速找到包含给定单词或除一个单词之外的所有单词)。
请先按照上面的维基百科链接。Tries
是最快的单词排序方法( n 单词,搜索 s ,O( n < / em>)创建trie,O(1)来搜索 s (或者如果你愿意,如果 a 是平均长度,O( an < / em>)用于搜索的trie和O( s ))。
快速简便地实现(优化)您的问题(类似的单词)包括
示例,使用car
,vars
。
构建特里(大字母意味着一个词在这里结束,而另一个可能继续)。 >
是后索引(前进),<
是前索引(后退)。在另一个例子中,我们可能还必须指出起始字母,为清楚起见,此处未提供
例如,C ++中的<
和>
为Mystruct *previous,*next
,意思是a > c < r
,您可以直接从a
转到c
,相反,也是从a
到R
。
1. c < a < R
2. a > c < R
3. > v < r < S
4. R > a > c
5. > v < S
6. v < a < r < S
7. S > r > a > v
严格查看 car ,trie可让您从1开始访问,然后找到 car (您也可以找到以 car ,但也有车内的任何东西 - 它不在示例中 - 但是例如 vicar 可以从c > i > v < a < R
找到。
要在允许1个字母的错误/缺失容差的同时进行搜索,您将从 s 的每个字母进行迭代,并计算连续的数量 - 或者通过跳过1个字母 - 来自 s 在特里。
寻找car
,
c
:在特里搜索c < a
和c < r
( s 中缺少字母)。要在单词 w 中接受错误的字母,请尝试在每次迭代时跳转错误的字母以查看ar
是否落后,这是O( w ) 。有两个字母,O( w ²)等...但是另一个级别的索引可以添加到trie中以考虑跳而不是字母 - 制作trie复杂,对内存贪婪。a
,然后r
:与上述相同,但也向后搜索这只是为了提供一个关于原理的想法 - 上面的例子可能有一些小问题(明天我会再次检查)。
答案 3 :(得分:1)
你可以这样做:
Foreach string in haystack Do offset := -1; matchedCharacters := 0; Foreach char in needle Do offset := PositionInString(string, char, offset+1); If offset = -1 Then Break; End; matchedCharacters := matchedCharacters + 1; End; If matchedCharacters > 0 Then // (partial) match found End; End;
使用 matchedCharacters ,您可以确定匹配的“度数”。如果它等于 needle 的长度, needle 中的所有字符也都在 string 中。如果还存储了第一个匹配字符的偏移量,则还可以通过从最后一个匹配字符偏移量的偏移量中减去第一个匹配字符的偏移量,按匹配字符的“密度”对结果进行排序;差异越小,匹配越密集。
答案 4 :(得分:1)
class Program {
static int ComputeLevenshteinDistance(string source, string target) {
if ((source == null) || (target == null)) return 0;
if ((source.Length == 0) || (target.Length == 0)) return 0;
if (source == target) return source.Length;
int sourceWordCount = source.Length;
int targetWordCount = target.Length;
int[,] distance = new int[sourceWordCount + 1, targetWordCount + 1];
// Step 2
for (int i = 0; i <= sourceWordCount; distance[i, 0] = i++);
for (int j = 0; j <= targetWordCount; distance[0, j] = j++);
for (int i = 1; i <= sourceWordCount; i++) {
for (int j = 1; j <= targetWordCount; j++) {
// Step 3
int cost = (target[j - 1] == source[i - 1]) ? 0 : 1;
// Step 4
distance[i, j] = Math.Min(Math.Min(distance[i - 1, j] + 1, distance[i, j - 1] + 1), distance[i - 1, j - 1] + cost);
}
}
return distance[sourceWordCount, targetWordCount];
}
static void Main(string[] args){
Console.WriteLine(ComputeLevenshteinDistance ("Stackoverflow","StuckOverflow"));
Console.ReadKey();
}
}