5

有没有办法让 difflib 在字符串匹配中考虑删除?

我已经尝试过,difflib.get_close_matches()但它不考虑近距离匹配输出中长度较短的字符串。例如

from difflib import get_close_matches as gcm

x = """Erfreulich
Erfreuliche
Erfreulicher
Erfreulicherem
Erfreulicheres
Erfreulicherweis
Erfreulicherweise
Erfreuliches
Erfreulichste"""

x = [i for i in x.split("\n")]

for i in x:
  print i, gcm(i,x)

输出:

Erfreulich ['Erfreulich', 'Erfreuliche', 'Erfreuliches']
Erfreuliche ['Erfreuliche', 'Erfreuliches', 'Erfreulicher']
Erfreulicher ['Erfreulicher', 'Erfreuliche', 'Erfreulicheres']
Erfreulicherem ['Erfreulicherem', 'Erfreulicheres', 'Erfreulicher']
Erfreulicheres ['Erfreulicheres', 'Erfreulicherweis', 'Erfreulicherem']
Erfreulicherweis ['Erfreulicherweis', 'Erfreulicherweise', 'Erfreulicheres']
Erfreulicherweise ['Erfreulicherweise', 'Erfreulicherweis', 'Erfreulicheres']
Erfreuliches ['Erfreuliches', 'Erfreuliche', 'Erfreulicheres']
Erfreulichste ['Erfreulichste', 'Erfreuliche', 'Erfreuliches']

请注意,对于 string ErfreulicherErfreulich尽管距离仅为 -1,但不被视为紧密匹配。

4

3 回答 3

6

文档中,n可以增加参数以获得更多匹配。有些单词较短,因此difflib考虑删除。

difflib.get_close_matches(word,可能性[, n][, cutoff])
返回最佳“足够好”匹配的列表。word 是需要紧密匹配的序列(通常是字符串),可能性是要匹配 word 的序列列表(通常是字符串列表)。

可选参数 n(默认 3)是要返回的最大匹配数;n 必须大于 0。

可选参数 cutoff (默认 0.6) 是 [0, 1] 范围内的浮点数。得分至少与单词相似的可能性将被忽略。

在一个列表中返回可能性中最好的(不超过 n 个)匹配,按相似度得分排序,最相似的在前。

这是与 相同的词gcm(i,x,6)

Erfreulicher ['Erfreulicher', 'Erfreuliche', 'Erfreulicheres', 'Erfreulicherem',
              'Erfreuliches', 'Erfreulich']
于 2013-11-13T15:01:11.660 回答
3

您应该接受 Mark Tolonen 的回答 - 他阅读了文档 ;-)

为了更深入地了解,请注意difflib相似性的概念与 Levenshtein 编辑距离无关 - 但也许这就是你真正想要的。当你说:

请注意,对于字符串 Erfreulicher,尽管距离仅为 -1,但 Erfreulich 不被视为紧密匹配。

我也不知道你心中的“距离”是什么概念。字符串相差 2 个字符,对吧?“-1”是神秘的。

difflib计算“相似度分数”,它是 0.0 到 1.0 范围内的浮点数。以下是如何使用您的列表查看它在内部执行的操作x

import difflib
s = difflib.SequenceMatcher()
s.set_seq2("Erfreulicher")
full = []
for i in x:
    s.set_seq1(i)
    full.append((s.ratio(), i))
full.sort(reverse=True)
for score, i in full:
    print "{:20} {:.3f}".format(i, score)

这是从最高相似度到最低排序的结果:

Erfreulicher         1.000
Erfreuliche          0.957
Erfreulicheres       0.923
Erfreulicherem       0.923
Erfreuliches         0.917
Erfreulich           0.909
Erfreulichste        0.880
Erfreulicherweis     0.857
Erfreulicherweise    0.828

正如文档所说,默认情况下get_close_matches()仅返回前 3 个。您要询问的特定单词恰好在列表中排在第六位,如果您告诉函数返回前 6 个(或 7 个等)匹配项,则会返回(见马克的回答)。

还记录了如何计算分数。由于“Erfreulich”是“Erfreulicher”的前缀,它简化为:

>>> 2.0 * len("Erfreulich") / (len("Erfreulich") + len("Erfreulicher"))
0.9090909090909091

列表中“Erfreulich”上方的所有字符串至少有一个共同的字符,这使得分子更大。分母对他们来说也更大,但是将分子增加(比如说)1 比将分母增加 1 对结果的影响更大。这可能符合您的直觉,也可能不符合您的直觉,但这就是它的工作原理;-)

于 2013-11-17T06:54:55.987 回答
2

I'm not a pyton developer, but it sounds like you need to compute levenshtein distances between strings. From the wiki:

the Levenshtein distance between two words is the minimum number of single-character edits (insertion, deletion, substitution) required to change one word into the other.

If you compute the distance from each word to each word you can always get the closest matches, based on what you define as "close". Now, as I said I'm not a pyton developer so I can't help you on the language specific implementation, but I found a python-levenshtein package.

于 2013-11-13T14:50:13.703 回答