我可以在 python 中以百分比精度执行“字符串包含 X”吗?

Posted

技术标签:

【中文标题】我可以在 python 中以百分比精度执行“字符串包含 X”吗?【英文标题】:Can I do a "string contains X" with a percentage accuracy in python? 【发布时间】:2012-06-06 15:03:47 【问题描述】:

我需要对一大段文本进行一些 OCR 并检查它是否包含某个字符串,但由于 OCR 的不准确,我需要它来检查它是否包含类似于该字符串的约 85% 匹配的内容。

例如,我可能会对一段文本进行 OCR 以确保它不包含 no information available,但 OCR 可能会看到 n0 inf0rmation available 或误解了一些字符。

有没有简单的方法在 Python 中做到这一点?

【问题讨论】:

【参考方案1】:

正如gauden 所发布的,SequenceMatcherdifflib 中是一个简单的方法。使用ratio(),返回一个介于01 之间的值,对应于两个字符串之间的相似性,来自文档:

其中 T 是两个序列中元素的总数,M 是 匹配的数量,这是 2.0*M / T。请注意,如果 序列是相同的,如果它们没有共同点,则为 0.0。

示例:

>>> import difflib
>>> difflib.SequenceMatcher(None,'no information available','n0 inf0rmation available').ratio()
0.91666666666666663

还有get_close_matches,它可能对你有用,你可以指定一个距离截断,它会从列表返回该距离内的所有匹配项:

>>> difflib.get_close_matches('unicorn', ['unicycle', 'uncorn', 'corny', 
                              'house'], cutoff=0.8)
['uncorn']
>>> difflib.get_close_matches('unicorn', ['unicycle'  'uncorn', 'corny',
                              'house'], cutoff=0.5)
['uncorn', 'corny', 'unicycle']

更新:找到部分子序列匹配

要找到与三个单词序列的紧密匹配,我会将文本拆分为单词,然后将它们分组为三个单词序列,然后应用difflib.get_close_matches,如下所示:

import difflib
text = "Here is the text we are trying to match across to find the three word
        sequence n0 inf0rmation available I wonder if we will find it?"    
words = text.split()
three = [' '.join([i,j,k]) for i,j,k in zip(words, words[1:], words[2:])]
print difflib.get_close_matches('no information available', three, cutoff=0.9)
#Oyutput:
['n0 inf0rmation available']

【讨论】:

就像我问高登一样,这可以用来检查子字符串匹配吗?我需要在充满文本的页面中找到“没有可用信息” @Jacxel - 我知道,要做到这一点,我可能会尝试在整个文本中循环 3 个单词匹配(第一次将文本拆分为单词,然后将每个三个单词的块组合在一起并尝试上述 @ 987654332@。然后回到拆分列表并再次分组,但将索引移动一个单词,然后重复..等..) @Jacxel - 更新以在文本中查找子序列 这不是很依赖正确的间距吗?例如,如果我的文本是 something no information availableandsomelongword,由于 ocr 在可用单词后面缺少空格,我会得到不匹配吗? @Jacxel - 它会发现那些匹配没有问题,只需将cutoff 参数更改为较低的值。如果 ocr 不能可靠地获得正确的间距,并且它是一个大问题(我怀疑它会变成..),那么您可以将没有空格的文本加入到 25 个长度的重叠字符串中(在类似的我如何用上面的文字完成它的方式),并在上面使用get_close_matches。真的,我认为您只需要尝试一些事情并适当地设置cutoff :)【参考方案2】:

difflib 标准库模块中的SequenceMatcher object 会直接给你一个比率:

【讨论】:

这可以用来检查子串匹配吗?我无法在检查中拆分字符串,它可能是 100 多个字符 帽子提示和 +1 给@fraxel,他已经掌握了这一切。【参考方案3】:

您可以计算Levenshtein distance。这是一个 Python 实现:http://pypi.python.org/pypi/python-Levenshtein/

【讨论】:

我考虑了 levenshtein 距离,但在我的情况下,它不太可能是拼写错误,更多的是奇怪的误解字符,所以看起来它可能做的工作比必要的多得多【参考方案4】:

我不知道任何可用的 python 库可以开箱即用,但您可能会找到一个(或找到 C 或 C++ 库并为其编写 Python 包装器)。

您还可以尝试推出自己的解决方案,基于“蛮力”逐个字符比较,使用定义两个给定字符之间“接近度”的规则并根据这些规则计算“准确性”(即“o " => "0" : 90% 准确率,"o" => "w" : 1% 准确率等),或者玩更多涉及 IA 的东西(如果你不熟悉 IA,“编程集体智能”这本书可以帮助您入门,尽管实施示例有些差)。

【讨论】:

【参考方案5】:

只是为了扩展 fraxel 的答案,这允许查找任意长度的字符串。很抱歉格式不好,所以很难。准确率是 findWords 中的截止值

def joinAllInTupleList(toupe):
#joinAllInTuple( [("hello", "world"),("face","book")]) = ['hello world', 'face book']
result=[]
for i in toupe:
    #i is the tuple itself
    carry = " "
    for z in i:
        #z is an element of i
        carry+=" "+z

    result.append(carry.strip())
return result

def findWords(text,wordSequence):

#setup
words = text.split(" ")

#get a list of subLists based on the length of wordSequence
#i.e. get all wordSequence length sub-sequences in text!

result=[]
numberOfWordsInSequence = len(wordSequence.strip().split(" ")) 
for i in range(numberOfWordsInSequence):
    result.append(words[i:])

# print 'result',result
c=zip(*result)

# print 'c',c
#join each tuple to a string
joined = joinAllInTupleList(c)

return difflib.get_close_matches(wordSequence, joined, cutoff=0.72389)

【讨论】:

以上是关于我可以在 python 中以百分比精度执行“字符串包含 X”吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 Golang 中以最小宽度浮动到字符串

用指数舍入一个双精度值

如何从 PHP 中的双精度数组中计算第 n 个百分位数?

在 Visual Studio 中以字节数组形式将 64 位双精度转换为 80 位双精度

Android Drawable:在 XML 文件中以百分比指定形状宽度?

在mysql中以百分比形式输出相同的列值