字串相似算法?

时间:2010-08-26 14:39:48

标签: algorithm string comparison filtering ranking

我需要比较2个字符串并计算它们的相似度,以过滤掉最相似字符串的列表。

EG。寻找“狗”将返回

  1. 该死
  2. 沼泽
  3. EG。寻找“破解”将返回

    1. 裂纹
    2. 俏皮话
    3. 插孔
    4. 嘎嘎
    5. 我遇到过:

      你知道更多的字符串相似度算法吗?

5 个答案:

答案 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 ))。

快速简便地实现(优化)您的问题(类似的单词)包括

  • 使用单词列表制作 trie ,将所有字母前后索引(参见下面的示例)
  • 要搜索 s ,请从 s [0]进行迭代,找到trie中的单词,然后 s [1]等。 。
  • 在trie中,如果找到的字母数为len( s ) - k ,则显示该单词,其中 k 是宽容(丢失1个字母,2 ......)。
  • 算法可以扩展到列表中的单词(见下文)

示例,使用carvars

构建特里(大字母意味着一个词在这里结束,而另一个可能继续)。 >是后索引(前进),<是前索引(后退)。在另一个例子中,我们可能还必须指出起始字母,为清楚起见,此处未提供 例如,C ++中的<>Mystruct *previous,*next,意思是a > c < r,您可以直接从a转到c,相反,也是从aR

  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 < ac < 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();
    }
}