给出两个字符串text1
和text2
public SOMEUSABLERETURNTYPE Compare(string text1, string text2)
{
// DO SOMETHING HERE TO COMPARE
}
示例:
第一个字符串:StackOverflow
第二个字符串:StaqOverflow
回归:相似度为91%
回报可以是%或类似的东西。
First String:简单文本测试
第二个字符串:复杂文本测试
返回:可以认为这些值相等
有什么想法吗?这样做的最佳方式是什么?
答案 0 :(得分:42)
有各种不同的方法可以做到这一点。请查看Wikipedia "String similarity measures" page以获取带算法的其他网页的链接。
我不认为这些算法中的任何一个都会考虑到声音 - 然而 - 所以“staq overflow”与“staw overflow”类似于“堆栈溢出”,尽管第一次更多在发音方面类似。
我刚刚发现another page提供了更多选项...特别是Soundex算法(Wikipedia)可能更接近你所追求的目标。
答案 1 :(得分:27)
Levenshtein distance可能就是你要找的东西。
答案 2 :(得分:14)
这是我为我正在开发的项目编写的一些代码。我需要根据字符串的单词知道字符串的相似比和相似比。 最后一个,我想知道最小字符串的单词相似度(所以如果所有单词都存在并且在较大的字符串中匹配,结果将是100%)和较大字符串的单词相似度比率(我称之为RealWordsRatio) )。 我使用Levenshtein算法来找到距离。到目前为止,代码未被优化,但它按预期工作。我希望你觉得它很有用。
public static int Compute(string s, string t)
{
int n = s.Length;
int m = t.Length;
int[,] d = new int[n + 1, m + 1];
// Step 1
if (n == 0)
{
return m;
}
if (m == 0)
{
return n;
}
// Step 2
for (int i = 0; i <= n; d[i, 0] = i++)
{
}
for (int j = 0; j <= m; d[0, j] = j++)
{
}
// Step 3
for (int i = 1; i <= n; i++)
{
//Step 4
for (int j = 1; j <= m; j++)
{
// Step 5
int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;
// Step 6
d[i, j] = Math.Min(
Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
d[i - 1, j - 1] + cost);
}
}
// Step 7
return d[n, m];
}
double GetSimilarityRatio(String FullString1, String FullString2, out double WordsRatio, out double RealWordsRatio)
{
double theResult = 0;
String[] Splitted1 = FullString1.Split(new char[]{' '}, StringSplitOptions.RemoveEmptyEntries);
String[] Splitted2 = FullString2.Split(new char[]{' '}, StringSplitOptions.RemoveEmptyEntries);
if (Splitted1.Length < Splitted2.Length)
{
String[] Temp = Splitted2;
Splitted2 = Splitted1;
Splitted1 = Temp;
}
int[,] theScores = new int[Splitted1.Length, Splitted2.Length];//Keep the best scores for each word.0 is the best, 1000 is the starting.
int[] BestWord = new int[Splitted1.Length];//Index to the best word of Splitted2 for the Splitted1.
for (int loop = 0; loop < Splitted1.Length; loop++)
{
for (int loop1 = 0; loop1 < Splitted2.Length; loop1++) theScores[loop, loop1] = 1000;
BestWord[loop] = -1;
}
int WordsMatched = 0;
for (int loop = 0; loop < Splitted1.Length; loop++)
{
String String1 = Splitted1[loop];
for (int loop1 = 0; loop1 < Splitted2.Length; loop1++)
{
String String2 = Splitted2[loop1];
int LevenshteinDistance = Compute(String1, String2);
theScores[loop, loop1] = LevenshteinDistance;
if (BestWord[loop] == -1 || theScores[loop, BestWord[loop]] > LevenshteinDistance) BestWord[loop] = loop1;
}
}
for (int loop = 0; loop < Splitted1.Length; loop++)
{
if (theScores[loop, BestWord[loop]] == 1000) continue;
for (int loop1 = loop + 1; loop1 < Splitted1.Length; loop1++)
{
if (theScores[loop1, BestWord[loop1]] == 1000) continue;//the worst score available, so there are no more words left
if (BestWord[loop] == BestWord[loop1])//2 words have the same best word
{
//The first in order has the advantage of keeping the word in equality
if (theScores[loop, BestWord[loop]] <= theScores[loop1, BestWord[loop1]])
{
theScores[loop1, BestWord[loop1]] = 1000;
int CurrentBest = -1;
int CurrentScore = 1000;
for (int loop2 = 0; loop2 < Splitted2.Length; loop2++)
{
//Find next bestword
if (CurrentBest == -1 || CurrentScore > theScores[loop1, loop2])
{
CurrentBest = loop2;
CurrentScore = theScores[loop1, loop2];
}
}
BestWord[loop1] = CurrentBest;
}
else//the latter has a better score
{
theScores[loop, BestWord[loop]] = 1000;
int CurrentBest = -1;
int CurrentScore = 1000;
for (int loop2 = 0; loop2 < Splitted2.Length; loop2++)
{
//Find next bestword
if (CurrentBest == -1 || CurrentScore > theScores[loop, loop2])
{
CurrentBest = loop2;
CurrentScore = theScores[loop, loop2];
}
}
BestWord[loop] = CurrentBest;
}
loop = -1;
break;//recalculate all
}
}
}
for (int loop = 0; loop < Splitted1.Length; loop++)
{
if (theScores[loop, BestWord[loop]] == 1000) theResult += Splitted1[loop].Length;//All words without a score for best word are max failures
else
{
theResult += theScores[loop, BestWord[loop]];
if (theScores[loop, BestWord[loop]] == 0) WordsMatched++;
}
}
int theLength = (FullString1.Replace(" ", "").Length > FullString2.Replace(" ", "").Length) ? FullString1.Replace(" ", "").Length : FullString2.Replace(" ", "").Length;
if(theResult > theLength) theResult = theLength;
theResult = (1 - (theResult / theLength)) * 100;
WordsRatio = ((double)WordsMatched / (double)Splitted2.Length) * 100;
RealWordsRatio = ((double)WordsMatched / (double)Splitted1.Length) * 100;
return theResult;
}
答案 3 :(得分:5)
我前一段时间写了Double Metaphone implementation in C#。你会发现它远远优于Soundex等。
Levenshtein距离也被提出,它是很多用途的很好的算法,但语音匹配并不是它真正的作用;它似乎只是因为语音相似的词通常也拼写相似。我做了analysis of various fuzzy matching algorithms你可能也觉得有用。
答案 4 :(得分:4)
要处理'声音相似',您可能需要使用Double Metaphone或soundex等语音算法来研究编码。我不知道在语音编码字符串上计算Levenshtein距离是否有益,但可能是有可能的。或者,你可以使用一种启发式方法:将字符串中的每个单词转换为其编码形式,并删除两个字符串中出现的任何单词,并在计算Levenshtein距离之前用单个表示替换它们。
答案 5 :(得分:3)
您可能会查找字符串“距离”,例如the Levenshtein distance。
答案 6 :(得分:3)
Perl模块Text::Phonetic具有各种算法的实现。
答案 7 :(得分:2)
Jeff Atwood wrote about looking for a similar solution用于确定维基帖的作者身份,这可能会帮助您缩小搜索范围。
答案 8 :(得分:2)
如果要比较SQL数据库中的值,可以使用 SOUNDEX 函数。如果您向Google查询SOUNDEX和C#,有些人已经为此编写了类似的函数和VB。
答案 9 :(得分:1)
我也要推荐Soundex,我过去曾用它来处理错误的城市名称。以下是一个很好的使用链接:http://whitepapers.zdnet.com/abstract.aspx?docid=352953
答案 10 :(得分:1)
如果您想要进行语音比较,请查看Soundex和Metaphone算法:http://www.blackbeltcoder.com/Articles/algorithms/phonetic-string-comparison-with-soundex
答案 11 :(得分:1)
Metaphone 3是Metaphone算法的第三代。它 从双倍的89%提高语音编码的准确性 Metaphone要 98%,对最常见的数据库进行测试 北方熟悉的英语单词,名称和非英语单词 美国。这产生了非常可靠的语音编码 美国发音。
Metaphone 3由Lawrence Philips设计和开发 设计并开发了原版Metaphone和Double Metaphone 算法