【发布时间】:2013-03-03 05:54:38
【问题描述】:
我在 C++ 中使用 Levenshtein 距离算法来比较两个字符串,以测量它们彼此之间的接近程度。但是,普通的 Levenshtein 距离算法不区分由空格分隔的单词边界。这导致距离计算比我想要的要小。我正在比较标题以查看它们彼此之间的接近程度,并且我希望算法不会将来自多个单词的字符视为匹配。
例如,如果我比较这两个字符串,我会得到以下结果,+ 表示匹配,- 表示不匹配:
Al Chertoff Et
Al Church Department of finance Et
+++++------+--++-----++-+------+++
Al Ch e rt of f Et
我得到了 20 与单词 "Chertoff" 匹配四个单词 "Church Department of finance" 的距离,而我真的希望通过不允许字符匹配多个单词来将它们彼此分开考虑与单词"Chertoff" 最匹配的单词"Department" 的距离为25,匹配三个字符:
Al Chertoff Et
Al Church Department of finance Et
+++--------+--++---------------+++
Al e rt Et
Ch off
我如何调整 Levenshtein 距离来完成此任务,或者是否有另一种更适合此的距离算法?也许在每个单词上单独使用 Levenshtein 距离并选择距离最小的单词?但是,如果在字符串深处匹配一个单词会导致后续单词匹配不佳,因为它们的匹配最好在字符串的较早位置?这可以通过将 Levenshtein 距离调整为单词级别来以某种方式完成吗?
例如,对于下面更复杂的例子,这个想法的最短距离是20:
Al Chertoff Deport Et
Al Church Department of finance Et
+++++----++++-++---------------+++
Al Ch Dep rt Et
ertoff o
而不是最大化"Chertoff"的匹配并获得更长的距离24:
Al Chertoff Deport Et
Al Church Department of finance Et
+++--------+--++-----+---------+++
Al e rt o Et
Ch off
Dep rt
我目前对 Levenshtein Distance 的实现如下:
size_t
levenshtein_distance(const std::string& a_compare1,
const std::string& a_compare2) {
const size_t length1 = a_compare1.size();
const size_t length2 = a_compare2.size();
std::vector<size_t> curr_col(length2 + 1);
std::vector<size_t> prev_col(length2 + 1);
// Prime the previous column for use in the following loop:
for (size_t idx2 = 0; idx2 < length2 + 1; ++idx2) {
prev_col[idx2] = idx2;
}
for (size_t idx1 = 0; idx1 < length1; ++idx1) {
curr_col[0] = idx1 + 1;
for (size_t idx2 = 0; idx2 < length2; ++idx2) {
const size_t compare = a_compare1[idx1] == a_compare2[idx2] ? 0 : 1;
curr_col[idx2 + 1] = std::min(std::min(curr_col[idx2] + 1,
prev_col[idx2 + 1] + 1),
prev_col[idx2] + compare);
}
curr_col.swap(prev_col);
}
return prev_col[length2];
}
【问题讨论】:
-
“但是,如果在字符串深处匹配一个单词会导致后续单词匹配不佳,因为它们的匹配最好在字符串的较早位置” 你能用一个例子解释一下这个说法吗?举一个你喜欢的匹配例子。
-
如第二个例子
"Al Church Department of finance Et"所示。 -
我有点晚了,你不能只是按单词分割和单独匹配单词吗?您实际上有两个编辑距离计算:一个在单词级别上,一个(在第一个内部)在两个单词内的字母级别上(仅当单词不匹配时)。 /EDIT 这听起来与斯蒂芬的回答很相似。
-
@KonradRudolph 是的,基本上就是这样,您只需要正确建模句子中单词的插入、删除和替换成本(因为单词中的字母它们总是 1,并且算法通常是写的有了这个假设)
标签: c++ algorithm stdstring levenshtein-distance heuristics