C# 除了计算距离外,如何度量两个字符串的相似性
我正在创建一个程序,检查单词是否简化(txt、msg等),如果简化,它会找到正确的拼写,如txt=text、msg=message。Iam使用c#中的NHunspell建议方法,建议所有可能的结果 问题是,如果我输入“txt”,结果是文本、tat、tot等。我不知道如何选择正确的单词。我使用了Levenshtein Distance(),但结果仍然是1 输入:txt 结果:text=1,ext=1 tit=1 你能帮我理解这些简化单词的意思或正确拼写吗?C# 除了计算距离外,如何度量两个字符串的相似性,c#,forms,algorithm,C#,Forms,Algorithm,我正在创建一个程序,检查单词是否简化(txt、msg等),如果简化,它会找到正确的拼写,如txt=text、msg=message。Iam使用c#中的NHunspell建议方法,建议所有可能的结果 问题是,如果我输入“txt”,结果是文本、tat、tot等。我不知道如何选择正确的单词。我使用了Levenshtein Distance(),但结果仍然是1 输入:txt 结果:text=1,ext=1 tit=1 你能帮我理解这些简化单词的意思或正确拼写吗? 示例:msg不是一个完整的解决方案,只是
示例:msg不是一个完整的解决方案,只是一个希望有用的建议
在我看来,人们不太可能使用与正确单词一样长的简化,因此您至少可以过滤掉所有长度的结果。我用您的样本数据测试了您的输入,只有
文本
的距离为25,而另一个距离为33。这是我的密码:
string input = "TXT";
string[] words = new[]{"text","tat","tot"};
var levenshtein = new Levenshtein();
const int maxDistance = 30;
var distanceGroups = words
.Select(w => new
{
Word = w,
Distance = levenshtein.iLD(w.ToUpperInvariant(), input)
})
.Where(x => x.Distance <= maxDistance)
.GroupBy(x => x.Distance)
.OrderBy(g => g.Key)
.ToList();
foreach (var topCandidate in distanceGroups.First())
Console.WriteLine("Word:{0} Distance:{1}", topCandidate.Word, topCandidate.Distance);
string input=“TXT”;
string[]words=new[]{“text”、“tat”、“tot”};
var levenshtein=新的levenshtein();
const int maxDistance=30;
var距离组=单词
.选择(w=>new
{
Word=w,
距离=levenshtein.iLD(w.toupper不变量(),输入)
})
.式中(x=>x.距离x.距离)
.OrderBy(g=>g.Key)
.ToList();
foreach(distanceGroups.First()中的var topCandidate)
WriteLine(“单词:{0}距离:{1}”,topCandidate.Word,topCandidate.Distance);
这是levenshtein课程:
public class Levenshtein
{
///*****************************
/// Compute Levenshtein distance
/// Memory efficient version
///*****************************
public int iLD(String sRow, String sCol)
{
int RowLen = sRow.Length; // length of sRow
int ColLen = sCol.Length; // length of sCol
int RowIdx; // iterates through sRow
int ColIdx; // iterates through sCol
char Row_i; // ith character of sRow
char Col_j; // jth character of sCol
int cost; // cost
/// Test string length
if (Math.Max(sRow.Length, sCol.Length) > Math.Pow(2, 31))
throw (new Exception("\nMaximum string length in Levenshtein.iLD is " + Math.Pow(2, 31) + ".\nYours is " + Math.Max(sRow.Length, sCol.Length) + "."));
// Step 1
if (RowLen == 0)
{
return ColLen;
}
if (ColLen == 0)
{
return RowLen;
}
/// Create the two vectors
int[] v0 = new int[RowLen + 1];
int[] v1 = new int[RowLen + 1];
int[] vTmp;
/// Step 2
/// Initialize the first vector
for (RowIdx = 1; RowIdx <= RowLen; RowIdx++)
{
v0[RowIdx] = RowIdx;
}
// Step 3
/// Fore each column
for (ColIdx = 1; ColIdx <= ColLen; ColIdx++)
{
/// Set the 0'th element to the column number
v1[0] = ColIdx;
Col_j = sCol[ColIdx - 1];
// Step 4
/// Fore each row
for (RowIdx = 1; RowIdx <= RowLen; RowIdx++)
{
Row_i = sRow[RowIdx - 1];
// Step 5
if (Row_i == Col_j)
{
cost = 0;
}
else
{
cost = 1;
}
// Step 6
/// Find minimum
int m_min = v0[RowIdx] + 1;
int b = v1[RowIdx - 1] + 1;
int c = v0[RowIdx - 1] + cost;
if (b < m_min)
{
m_min = b;
}
if (c < m_min)
{
m_min = c;
}
v1[RowIdx] = m_min;
}
/// Swap the vectors
vTmp = v0;
v0 = v1;
v1 = vTmp;
}
// Step 7
/// Value between 0 - 100
/// 0==perfect match 100==totaly different
///
/// The vectors where swaped one last time at the end of the last loop,
/// that is why the result is now in v0 rather than in v1
//System.Console.WriteLine("iDist=" + v0[RowLen]);
int max = System.Math.Max(RowLen, ColLen);
return ((100 * v0[RowLen]) / max);
}
///*****************************
/// Compute the min
///*****************************
private int Minimum(int a, int b, int c)
{
int mi = a;
if (b < mi)
{
mi = b;
}
if (c < mi)
{
mi = c;
}
return mi;
}
///*****************************
/// Compute Levenshtein distance
///*****************************
public int LD(String sNew, String sOld)
{
int[,] matrix; // matrix
int sNewLen = sNew.Length; // length of sNew
int sOldLen = sOld.Length; // length of sOld
int sNewIdx; // iterates through sNew
int sOldIdx; // iterates through sOld
char sNew_i; // ith character of sNew
char sOld_j; // jth character of sOld
int cost; // cost
/// Test string length
if (Math.Max(sNew.Length, sOld.Length) > Math.Pow(2, 31))
throw (new Exception("\nMaximum string length in Levenshtein.LD is " + Math.Pow(2, 31) + ".\nYours is " + Math.Max(sNew.Length, sOld.Length) + "."));
// Step 1
if (sNewLen == 0)
{
return sOldLen;
}
if (sOldLen == 0)
{
return sNewLen;
}
matrix = new int[sNewLen + 1, sOldLen + 1];
// Step 2
for (sNewIdx = 0; sNewIdx <= sNewLen; sNewIdx++)
{
matrix[sNewIdx, 0] = sNewIdx;
}
for (sOldIdx = 0; sOldIdx <= sOldLen; sOldIdx++)
{
matrix[0, sOldIdx] = sOldIdx;
}
// Step 3
for (sNewIdx = 1; sNewIdx <= sNewLen; sNewIdx++)
{
sNew_i = sNew[sNewIdx - 1];
// Step 4
for (sOldIdx = 1; sOldIdx <= sOldLen; sOldIdx++)
{
sOld_j = sOld[sOldIdx - 1];
// Step 5
if (sNew_i == sOld_j)
{
cost = 0;
}
else
{
cost = 1;
}
// Step 6
matrix[sNewIdx, sOldIdx] = Minimum(matrix[sNewIdx - 1, sOldIdx] + 1, matrix[sNewIdx, sOldIdx - 1] + 1, matrix[sNewIdx - 1, sOldIdx - 1] + cost);
}
}
// Step 7
/// Value between 0 - 100
/// 0==perfect match 100==totaly different
//System.Console.WriteLine("Dist=" + matrix[sNewLen, sOldLen]);
int max = System.Math.Max(sNewLen, sOldLen);
return (100 * matrix[sNewLen, sOldLen]) / max;
}
}
公共类Levenshtein
{
///*****************************
///计算Levenshtein距离
///内存有效版本
///*****************************
公共int iLD(字符串sRow、字符串sCol)
{
int RowLen=sRow.Length;//sRow的长度
int ColLen=sCol.Length;//sCol的长度
int RowIdx;//遍历sRow
int ColIdx;//遍历sCol
char Row_i;//sRow的第i个字符
char Col_j;//sCol的第j个字符
int cost;//成本
///测试字符串长度
如果(数学最大值(sRow.Length,sCol.Length)>数学功率(2,31))
抛出(新异常(“\n Levenshtein.iLD中的最大字符串长度为“+Math.Pow(2,31)+”。\n您的字符串长度为“+Math.Max(sRow.length,sCol.length)+”);
//第一步
如果(RowLen==0)
{
返回科伦;
}
如果(ColLen==0)
{
返回RowLen;
}
///创建两个向量
int[]v0=新int[RowLen+1];
int[]v1=新的int[RowLen+1];
int[]vTmp;
///步骤2
///初始化第一个向量
对于(RowIdx=1;RowIdx在我的评论上展开),您可以使用regex搜索作为输入“展开”的结果。类似如下:
private int stringSimilarity(string input, string result)
{
string regexPattern = ""
foreach (char c in input)
regexPattern += input + ".*"
Match match = Regex.Match(result, regexPattern,
RegexOptions.IgnoreCase);
if (match.Success)
return 1;
else
return 0;
}
忽略1和0-我不知道相似性评估是如何工作的。您确实需要实现SQL中存在的SOUNDEX
例程。我在以下代码中完成了这一点:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Soundex
{
class Program
{
static char[] ignoreChars = new char[] { 'a', 'e', 'h', 'i', 'o', 'u', 'w', 'y' };
static Dictionary<char, int> charVals = new Dictionary<char, int>()
{
{'b',1},
{'f',1},
{'p',1},
{'v',1},
{'c',2},
{'g',2},
{'j',2},
{'k',2},
{'q',2},
{'s',2},
{'x',2},
{'z',2},
{'d',3},
{'t',3},
{'l',4},
{'m',5},
{'n',5},
{'r',6}
};
static void Main(string[] args)
{
Console.WriteLine(Soundex("txt"));
Console.WriteLine(Soundex("text"));
Console.WriteLine(Soundex("ext"));
Console.WriteLine(Soundex("tit"));
Console.WriteLine(Soundex("Cammmppppbbbeeelll"));
}
static string Soundex(string s)
{
s = s.ToLower();
StringBuilder sb = new StringBuilder();
sb.Append(s.First());
foreach (var c in s.Substring(1))
{
if (ignoreChars.Contains(c)) { continue; }
// if the previous character yields the same integer then skip it
if ((int)char.GetNumericValue(sb[sb.Length - 1]) == charVals[c]) { continue; }
sb.Append(charVals[c]);
}
return string.Join("", sb.ToString().Take(4)).PadRight(4, '0');
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
名称空间Soundex
{
班级计划
{
静态字符[]ignoreChars=新字符[]{'a','e','h','i','o','u','w','y'};
静态字典charVals=新字典()
{
{'b',1},
{'f',1},
{'p',1},
{'v',1},
{'c',2},
{'g',2},
{'j',2},
{'k',2},
{'q',2},
{s',2},
{'x',2},
{'z',2},
{'d',3},
{'t',3},
{'l',4},
{m',5},
{'n',5},
{'r',6}
};
静态void Main(字符串[]参数)
{
Console.WriteLine(Soundex(“txt”);
Console.WriteLine(Soundex(“文本”);
控制台写入线(Soundex(“ext”));
控制台写入线(Soundex(“tit”);
控制台写入线(Soundex(“cammppbbbeelll”);
}
静态字符串Soundex(字符串s)
{
s=s.ToLower();
StringBuilder sb=新的StringBuilder();
某人附加(s.First());
foreach(s.Substring(1)中的var c)
{
如果(ignoreChars.Contains(c)){continue;}
//如果前一个字符产生相同的整数,则跳过它
如果((int)char.GetNumericValue(sb[sb.Length-1])==charVals[c]){continue;}
sb.追加(charVals[c]);
}
返回字符串.Join(“,sb.ToString().Take(4)).PadRight(4,'0');
}
}
}
请看,使用此代码,您给出的示例中唯一匹配的是text
。运行控制台应用程序,您将看到输出(即txt
将匹配text
)。我认为像word这样的程序用于纠正拼写的一种方法是使用NLP(自然语言处理)获取拼写错误上下文中使用的名词/形容词顺序的技巧。然后将其与已知的句子结构进行比较,他们可以估计拼写错误是名词的概率为70%,并使用该信息过滤更正的拼写
看起来是一个很好的图书馆,但我还没有机会去摆弄它。顺便说一句,为了建立一个已知句子结构的图书馆,我们在uni将我们的算法应用到公共领域的书籍中
查看我在SO(,)上找到的loads,除了Levenshtein distance之外,还有更多算法选项可供使用。似乎是改进它的一种方法,那就是检查每个结果是否至少包含输入的所有字符。我同意Corak的观点-例如,您给出的3个结果的正确选项,“text”,“ext”和