优雅的方式匹配两个通配字符串

Cla*_*diu 7 python regex string string-matching

我正在从两个不同的来源中删除一些文本.他们每个人都可以在不同的地方犯错,他们不会识别一封信/一组信件.如果他们不认识某事,那就换成了?例如,如果单词是Roflcopter,则一个源可能返回Ro?copter,而另一个源,Roflcop?er.我想要一个函数来返回两个匹配是否相同,允许多个?s.例:

match("Ro?copter", "Roflcop?er") --> True
match("Ro?copter", "Roflcopter") --> True
match("Roflcopter", "Roflcop?er") --> True
match("Ro?co?er", "Roflcop?er") --> True
Run Code Online (Sandbox Code Playgroud)

到目前为止,我可以使用正则表达式将一个OCR与一个完美的OCR匹配:

>>> def match(tn1, tn2):
    tn1re = tn1.replace("?", ".{0,4}")
    tn2re = tn2.replace("?", ".{0,4}")

    return bool(re.match(tn1re, tn2) or re.match(tn2re, tn1))

>>> match("Roflcopter", "Roflcop?er")
True
>>> match("R??lcopter", "Roflcopter")
True
Run Code Online (Sandbox Code Playgroud)

但是当它们都在不同的地方时,这不起作用:

>>> match("R??lcopter", "Roflcop?er")
False
Run Code Online (Sandbox Code Playgroud)

Cla*_*diu 2

感谢 Hamish Grubijan 提出这个想法。每一个 ?在我的 OCR 名称中,名称可以是 0 到 3 个字母。我所做的是将每个字符串扩展为可能扩展的列表:

>>> list(expQuestions("?flcopt?"))
['flcopt', 'flcopt@', 'flcopt@@', 'flcopt@@@', '@flcopt', '@flcopt@', '@flcopt@@', '@flcopt@@@', '@@flcopt', '@@flcopt@', '@@flcopt@@', '@@flcopt@@@', '@@@flcopt', '@@@flcopt@', '@@@flcopt@@', '@@@flcopt@@@']
Run Code Online (Sandbox Code Playgroud)

然后我扩展两者并使用他的匹配函数,我称之为matchats

def matchOCR(l, r):
    for expl in expQuestions(l):
        for expr in expQuestions(r):
            if matchats(expl, expr):
                return True
    return False
Run Code Online (Sandbox Code Playgroud)

按预期工作:

>>> matchOCR("Ro?co?er", "?flcopt?")
True
>>> matchOCR("Ro?co?er", "?flcopt?z")
False
>>> matchOCR("Ro?co?er", "?flc?pt?")
True
>>> matchOCR("Ro?co?e?", "?flc?pt?")
True
Run Code Online (Sandbox Code Playgroud)


匹配函数:

def matchats(l, r):
    """Match two strings with @ representing exactly 1 char"""
    if len(l) != len(r): return False
    for i, c1 in enumerate(l):
        c2 = r[i]
        if c1 == "@" or c2 == "@": continue
        if c1 != c2: return False
    return True
Run Code Online (Sandbox Code Playgroud)

和扩展函数,它cartesian_product在哪里:

def expQuestions(s):
    """For OCR w/ a questionmark in them, expand questions with
    @s for all possibilities"""
    numqs = s.count("?")

    blah = list(s)
    for expqs in cartesian_product([(0,1,2,3)]*numqs):
        newblah = blah[:]
        qi = 0
        for i,c in enumerate(newblah):
            if newblah[i] == '?':
                newblah[i] = '@'*expqs[qi]
                qi += 1
        yield "".join(newblah)
Run Code Online (Sandbox Code Playgroud)