如何在Python列表中搜索不连续的字符?

时间:2016-08-01 16:09:15

标签: python

我正在尝试搜索列表(DB)以查找文本片段的可能匹配项。例如,我有一个带有文本“邪恶者”的数据库。我想使用用户输入来搜索数据库中的任何可能的匹配,并给出答案。如果用户输入“hello”,则没有可能的匹配。如果用户输入“evil”,那么可能的匹配是邪恶的,信心为57%(7个字母中有4个匹配),依此类推。

但是,我还想要一种匹配输入文本的方法,例如“evxxman”。 evxxman的7个字符中的5个与DB中的文本“evilman”匹配。但是python中的简单检查会说没有匹配,因为它只输出连续匹配的文本。我希望这是有道理的。感谢

以下是我的代码:

db = []
possible_signs = []
db.append("evilman")

text = raw_input()

for s in db:
 if text in s:
  if len(text) >= len(s)/2:                              
   possible_signs.append(s)

    count += 1
    confidence = (float(len(text)) / float(len(s))) * 100
    print "Confidence:", '%.2f' %(confidence), "<possible match:>", possible_signs[0] 

4 个答案:

答案 0 :(得分:1)

要查找质量评估的匹配项,请查看difflib.SequenceMatcher.ratio和朋友 - 这些功能可能不是最快的匹配检查程序,但它们很容易使用。

从difflib docs复制的示例

>>> s = SequenceMatcher(None, "abcd", "bcde")
>>> s.ratio()
0.75
>>> s.quick_ratio()
0.75
>>> s.real_quick_ratio()
1.0

答案 1 :(得分:1)

根据您的描述和示例,在我看来,您实际上正在寻找类似Levenshtein (or edit) distance的内容。请注意,它并没有给出你指定的分数,但我认为它给出了你真正想要的分数。

有几个包有效地实现了这一点,例如distance

In [1]: import distance

In [2]: distance.levenshtein('evilman', 'hello')
Out[2]: 6L

In [3]: distance.levenshtein('evilman', 'evil')
Out[3]: 3L

In [4]: distance.levenshtein('evilman', 'evxxman')
Out[4]: 2L

请注意,该库包含多个相似度量,例如,jaccard和sorensen默认返回标准化值:

>>> distance.sorensen("decide", "resize")
0.5555555555555556
>>> distance.jaccard("decide", "resize")
0.7142857142857143

答案 2 :(得分:1)

创建一个while循环并跟踪两个迭代器,一个用于关键字(“evil”),另一个用于查询词(“evilman”)。这是一些伪代码:

key = "evil"
query = "evilman"
key_iterator = 0
query_iterator = 0
confidence_score = 0

while( key_iterator < key.length && query_iterator < query.length ) {
    if (key[key_iterator] == query[query_iterator]) {
        confidence_score++
        key_iterator++
    }
    query_iterator++
}

// If we didnt reach the end of the key
if (key_iterator != key.length) { 
    confidence_score = 0
}
print ("Confidence: " + confidence_score + " out of " + query.length)

答案 3 :(得分:1)

这第一个版本似乎符合您的例子。它使字符串&#34;滑动&#34;相互对立,并计算相同字符的数量。 通过将字符数除以参考字符串长度来进行比率。添加最大值和瞧。 为数据库中的每个字符串调用它。

def commonChars(txt, ref):
    txtLen = len(txt)
    refLen = len(ref)
    r = 0
    for i in range(refLen + (txtLen - 1)):
        rStart = abs(min(0, txtLen - i - 1))
        tStart = txtLen -i - 1 if i < txtLen else 0
        l = min(txtLen - tStart, refLen - rStart)
        c = 0
        for j in range(l):
            if txt[tStart + j] == ref[rStart + j]:
                c += 1
        r = max(r, c / refLen)
    return r

print(commonChars('evxxman', 'evilman')) # 0.7142857142857143
print(commonChars('evil', 'evilman')) # 0.5714285714285714
print(commonChars('man', 'evilman')) # 0.42857142857142855
print(commonChars('batman', 'evilman')) # 0.42857142857142855
print(commonChars('batman', 'man')) # 1.0

第二个版本产生相同的结果,但使用其他答案中提到的difflib。 它计算匹配块,求和它们的长度,并根据参考长度计算比率。

import difflib

def commonBlocks(txt, ref):
    matcher = difflib.SequenceMatcher(a=txt, b=ref)
    matchingBlocks = matcher.get_matching_blocks()
    matchingCount = sum([b.size for b in matchingBlocks])
    return matchingCount / len(ref)

print(commonBlocks('evxxman', 'evilman')) # 0.7142857142857143
print(commonBlocks('evxxxxman', 'evilman')) # 0.7142857142857143

如上面的调用所示,行为略有不同。 &#34;孔&#34;忽略匹配块之间,并且不改变最终比率。