在Python中匹配2个正则表达式

发布于 2021-01-29 15:26:13

是否可以在Python中匹配2个正则表达式?

例如,我有一个用例,其中我需要比较两个这样的表达式:

re.match('google\.com\/maps', 'google\.com\/maps2', re.IGNORECASE)

我希望会返回一个RE对象。

但显然,Python希望将字符串作为第二个参数。有没有办法做到这一点,还是对正则表达式匹配方式的限制?


背景:我有一个与字符串匹配的正则表达式[r1,r2,r3,…]的列表,我需要找出哪个表达式与给定字符串最匹配。我以为可以使它工作的方式是:
(1)将r1与r2匹配。
(2)然后将r2与r1匹配。
如果两者都匹配,我们有一个“领带”。如果仅(1)个有效,则r1比r2更“匹配”,反之亦然。
我会在整个列表中循环(1)和(2)。

我承认这有点令人费解(主要是因为我的描述可能不连贯),但是如果有人可以让我对如何实现这一目标有所了解,我将不胜感激。谢谢!

关注者
0
被浏览
209
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    除了上的语法说明外re.match,我想我理解您正在努力采用两个或多个未知(用户输入)正则表达式,并对字符串进行更“特定”的匹配分类。

    回想一下,Python正则表达式确实是一种计算机程序。大多数现代形式(包括Python的正则表达式)都基于Perl。Perl的正则表达式具有递归,回溯和其他形式的琐碎检查。确实,流氓正则表达式可以用作拒绝服务攻击的一种形式。

    要在自己的计算机上查看此消息,请尝试:

    >>> re.match(r'^(a+)+$','a'*24+'!')
    

    在我的计算机上大约需要1秒钟。现在增加了24'a'*24一个位数量较多,说28。那需要更长的时间。尝试48…您可能现在需要CTRL+
    C。时间随着a的增加而增加,实际上是指数的。

    您可以在Russ
    Cox
    的精彩论文“正则表达式匹配可以简单而快速”中阅读有关此问题的更多信息。Russ
    Cox是Goggle工程师,于2006年建立了Google Code
    Search
    。正如Cox所言,请考虑将正则表达式'a?'*33 + 'a'*33'a'*99带有awk和Perl(或Python或PCRE或Java或PHP或…)的字符串匹配。Awk的匹配时间为200微秒,但Perl由于需要进行指数追溯,因此需要10到15
    年的时间

    因此结论是: 这取决于! 您说的是 更具体的
    匹配是什么意思?看看RE2中Cox的一些正则表达式简化技术。如果您的项目足够大,可以编写自己的库(或使用RE2),并且您愿意限制使用的正则表达式语法(即没有回溯或递归形式),那么我认为答案是,您可以将“更好的匹配”分类以各种方式。

    如果您正在寻找一种简单的方法来声明(regex_3 <regex_1
    <regex_2)当使用Python或Perl的regex语言与某些字符串匹配时,我认为答案是非常困难的(即,此问题NP
    Complete

    编辑

    我上面说的一切都是真的!
    但是,这是根据“形式”的一种形式对匹配的正则表达式进行排序的一种方法:从正则表达式到字符串要进行多少次编辑。编辑次数越多(或Levenshtein距离越大),则正则表达式的“特定性”越小。

    您可以判断这是否可行(我不知道“特定”对您的申请意味着什么):

    import re
    
    def ld(a,b):
        "Calculates the Levenshtein distance between a and b."
        n, m = len(a), len(b)
        if n > m:
            # Make sure n <= m, to use O(min(n,m)) space
            a,b = b,a
            n,m = m,n
    
        current = range(n+1)
        for i in range(1,m+1):
            previous, current = current, [i]+[0]*n
            for j in range(1,n+1):
                add, delete = previous[j]+1, current[j-1]+1
                change = previous[j-1]
                if a[j-1] != b[i-1]:
                    change = change + 1
                current[j] = min(add, delete, change)      
        return current[n]
    
    s='Mary had a little lamb'    
    d={}
    regs=[r'.*', r'Mary', r'lamb', r'little lamb', r'.*little lamb',r'\b\w+mb',
            r'Mary.*little lamb',r'.*[lL]ittle [Ll]amb',r'\blittle\b',s,r'little']
    
    for reg in regs:
        m=re.search(reg,s)
        if m:
            print "'%s' matches '%s' with sub group '%s'" % (reg, s, m.group(0))
            ld1=ld(reg,m.group(0))
            ld2=ld(m.group(0),s)
            score=max(ld1,ld2)
            print "  %i edits regex->match(0), %i edits match(0)->s" % (ld1,ld2)
            print "  score: ", score
            d[reg]=score
            print
        else:
            print "'%s' does not match '%s'" % (reg, s)
    
    print "   ===== %s =====    === %s ===" % ('RegEx'.center(10),'Score'.center(10))
    
    for key, value in sorted(d.iteritems(), key=lambda (k,v): (v,k)):
        print "   %22s        %5s" % (key, value)
    

    该程序获取正则表达式的列表,并与字符串进行匹配Mary had a little lamb

    以下是从“最具体”到“最不具体”的排序排名:

       =====   RegEx    =====    ===   Score    ===
       Mary had a little lamb            0
            Mary.*little lamb            7
                .*little lamb           11
                  little lamb           11
          .*[lL]ittle [Ll]amb           15
                   \blittle\b           16
                       little           16
                         Mary           18
                      \b\w+mb           18
                         lamb           18
                           .*           22
    

    这基于(可能是简单的)假设:a)从正则表达式本身到匹配子字符串的编辑次数(Levenshtein距离)是通配符扩展或替换的结果;b)从匹配子字符串到初始字符串的编辑。(只要一个)

    作为两个简单的示例:

    1. .*(或.*.*or.*?.*等)对字符串的大量修改,实际上等于字符串的长度。这是最大可能的编辑次数,最高的得分和最少的“特定”正则表达式。
    2. 字符串本身相对于字符串的正则表达式尽可能具体。没有修改将一个更改为另一个,结果为0或最低分数。

    如上所述,这很简单。锚应增加特异性,但在这种情况下则不可以。短字符串不起作用,因为通配符可能比字符串长。

    编辑2

    使用sre_parsePython中未记录的模块,我得到了锚点解析,可以很好地工作。类型>>> help(sre_parse),如果你想了解更多…

    这是该模块下面的goto workerre模块。自2001年以来,它已出现在每个Python发行版中,包括所有P3k版本。它 可能
    会消失,但我认为这不太可能…

    这是修改后的清单:

    import re
    import sre_parse
    
    def ld(a,b):
        "Calculates the Levenshtein distance between a and b."
        n, m = len(a), len(b)
        if n > m:
            # Make sure n <= m, to use O(min(n,m)) space
            a,b = b,a
            n,m = m,n
    
        current = range(n+1)
        for i in range(1,m+1):
            previous, current = current, [i]+[0]*n
            for j in range(1,n+1):
                add, delete = previous[j]+1, current[j-1]+1
                change = previous[j-1]
                if a[j-1] != b[i-1]:
                    change = change + 1
                current[j] = min(add, delete, change)      
        return current[n]
    
    s='Mary had a little lamb'    
    d={}
    regs=[r'.*', r'Mary', r'lamb', r'little lamb', r'.*little lamb',r'\b\w+mb',
            r'Mary.*little lamb',r'.*[lL]ittle [Ll]amb',r'\blittle\b',s,r'little',
            r'^.*lamb',r'.*.*.*b',r'.*?.*',r'.*\b[lL]ittle\b \b[Ll]amb',
            r'.*\blittle\b \blamb$','^'+s+'$']
    
    for reg in regs:
        m=re.search(reg,s)
        if m:
            ld1=ld(reg,m.group(0))
            ld2=ld(m.group(0),s)
            score=max(ld1,ld2)
            for t, v in sre_parse.parse(reg):
                if t=='at':      # anchor...
                    if v=='at_beginning' or 'at_end':
                        score-=1   # ^ or $, adj 1 edit
    
                    if v=='at_boundary': # all other anchors are 2 char
                        score-=2
    
            d[reg]=score
        else:
            print "'%s' does not match '%s'" % (reg, s)
    
    print
    print "   ===== %s =====    === %s ===" % ('RegEx'.center(15),'Score'.center(10))
    
    for key, value in sorted(d.iteritems(), key=lambda (k,v): (v,k)):
        print "   %27s        %5s" % (key, value)
    

    令人讨厌的RegEx:

       =====      RegEx      =====    ===   Score    ===
            Mary had a little lamb            0
          ^Mary had a little lamb$            0
              .*\blittle\b \blamb$            6
                 Mary.*little lamb            7
         .*\b[lL]ittle\b \b[Ll]amb           10
                        \blittle\b           10
                     .*little lamb           11
                       little lamb           11
               .*[lL]ittle [Ll]amb           15
                           \b\w+mb           15
                            little           16
                           ^.*lamb           17
                              Mary           18
                              lamb           18
                           .*.*.*b           21
                                .*           22
                             .*?.*           22
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看