Levenshtein 比较字符串而不改变数字
Levenshtein compare strings without changing numbers
我正在寻找一种方法来查找相似的符号名称,其中这些名称通常是文本和数字的组合,例如 "value1"、“_value2”、"test_5" 等
为了找到相似的名称,我尝试使用 Levenshtein 距离,但对于该算法,“_value1”和“.value1”之间的差异与“_value1”和“_value8”相同。
有没有办法在不允许更改数字的情况下比较字符串?
我目前使用的代码来自http://www.dotnetperls.com/levenshtein
提前致谢!
您可以为任何涉及数字的不等比较提供非常高的距离,例如 200。这将使“_text1”和“.text1”之间的距离保持为 1(相似),但距离为 200(非常"text1" 和 "text10".
之间不相似)
您可以通过更改第二步来做到这一点...
// Step 2
d[0, 0] = 0;
for (int i = 1; i <= n; i++);
{
if('0' <= s[i - 1] && s[i - 1] <= '9')
d[i, 0] = d[i-1, 0] + 200;
else
d[i, 0] = d[i-1, 0] + 1;
}
for (int j = 1; j <= m; j++)
{
if('0' <= t[j - 1] && t[j - 1] <= '9')
d[0, j] = d[0, j-1] + 200;
else
d[0, j] = d[0, j-1] + 1;
}
...还有五个...
// Step 5
int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;
if(('0' <= t[j - 1] && t[j - 1] <= '9') ||
'0' <= s[i - 1] && s[i - 1] <= '9'))
cost *= 200;
关于Kittsil的回答,这是我的完整解决方案。
我不确定它是否完全正确,但它似乎对我有用。
ushort n = (ushort)s.Length;
ushort m = (ushort)t.Length;
ushort[,] d = new ushort[n + 1, m + 1];
// Step 1
if (n == 0)
{
return m;
}
if (m == 0)
{
return n;
}
// Step 2
d[0, 0] = 0;
for (int i = 1; i <= n; i++)
{
if ('0' <= s[i - 1] && s[i - 1] <= '9')
d[i, 0] = (ushort)(d[i - 1, 0] + 200);
else
d[i, 0] = (ushort)(d[i - 1, 0] + 1);
}
for (int j = 1; j <= m; j++)
{
if ('0' <= t[j - 1] && t[j - 1] <= '9')
d[0, j] = (ushort)(d[0, j - 1] + 200);
else
d[0, j] = (ushort)(d[0, j - 1] + 1);
}
// Step 3
for (int i = 1; i <= n; i++)
{
//Step 4
for (int j = 1; j <= m; j++)
{
// Step 5
bool isIdentical = t[j - 1] == s[i - 1];
bool isNumber = ('0' <= t[j - 1] && t[j - 1] <= '9') || ('0' <= s[i - 1] && s[i - 1] <= '9');
int cost1 = isIdentical ? 0 : (isNumber ? 200 : 1);
int cost2 = isNumber ? 200 : 1;
// Step 6
d[i, j] = (ushort)(Math.Min(Math.Min(d[i - 1, j] + cost2, d[i, j - 1] + cost2), d[i - 1, j - 1] + cost1));
}
}
// Step 7
return d[n, m];
我正在寻找一种方法来查找相似的符号名称,其中这些名称通常是文本和数字的组合,例如 "value1"、“_value2”、"test_5" 等
为了找到相似的名称,我尝试使用 Levenshtein 距离,但对于该算法,“_value1”和“.value1”之间的差异与“_value1”和“_value8”相同。 有没有办法在不允许更改数字的情况下比较字符串?
我目前使用的代码来自http://www.dotnetperls.com/levenshtein
提前致谢!
您可以为任何涉及数字的不等比较提供非常高的距离,例如 200。这将使“_text1”和“.text1”之间的距离保持为 1(相似),但距离为 200(非常"text1" 和 "text10".
之间不相似)您可以通过更改第二步来做到这一点...
// Step 2
d[0, 0] = 0;
for (int i = 1; i <= n; i++);
{
if('0' <= s[i - 1] && s[i - 1] <= '9')
d[i, 0] = d[i-1, 0] + 200;
else
d[i, 0] = d[i-1, 0] + 1;
}
for (int j = 1; j <= m; j++)
{
if('0' <= t[j - 1] && t[j - 1] <= '9')
d[0, j] = d[0, j-1] + 200;
else
d[0, j] = d[0, j-1] + 1;
}
...还有五个...
// Step 5
int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;
if(('0' <= t[j - 1] && t[j - 1] <= '9') ||
'0' <= s[i - 1] && s[i - 1] <= '9'))
cost *= 200;
关于Kittsil的回答,这是我的完整解决方案。 我不确定它是否完全正确,但它似乎对我有用。
ushort n = (ushort)s.Length;
ushort m = (ushort)t.Length;
ushort[,] d = new ushort[n + 1, m + 1];
// Step 1
if (n == 0)
{
return m;
}
if (m == 0)
{
return n;
}
// Step 2
d[0, 0] = 0;
for (int i = 1; i <= n; i++)
{
if ('0' <= s[i - 1] && s[i - 1] <= '9')
d[i, 0] = (ushort)(d[i - 1, 0] + 200);
else
d[i, 0] = (ushort)(d[i - 1, 0] + 1);
}
for (int j = 1; j <= m; j++)
{
if ('0' <= t[j - 1] && t[j - 1] <= '9')
d[0, j] = (ushort)(d[0, j - 1] + 200);
else
d[0, j] = (ushort)(d[0, j - 1] + 1);
}
// Step 3
for (int i = 1; i <= n; i++)
{
//Step 4
for (int j = 1; j <= m; j++)
{
// Step 5
bool isIdentical = t[j - 1] == s[i - 1];
bool isNumber = ('0' <= t[j - 1] && t[j - 1] <= '9') || ('0' <= s[i - 1] && s[i - 1] <= '9');
int cost1 = isIdentical ? 0 : (isNumber ? 200 : 1);
int cost2 = isNumber ? 200 : 1;
// Step 6
d[i, j] = (ushort)(Math.Min(Math.Min(d[i - 1, j] + cost2, d[i, j - 1] + cost2), d[i - 1, j - 1] + cost1));
}
}
// Step 7
return d[n, m];