代码之家  ›  专栏  ›  技术社区  ›  dbr

替代`match=re.match();如果匹配:。..“成语?

  •  34
  • dbr  · 技术社区  · 17 年前

    import re
    match = re.match("(\d+)g", "123g")
    if match is not None:
        print match.group(1)
    

    match

    像Perl这样的语言通过创建新的 $1 .. $9 匹配组的变量,如。。

    if($blah ~= /(\d+)g/){
        print $1
    }
    

    this reddit comment ,

    with re_context.match('^blah', s) as match:
        if match:
            ...
        else:
            ...
    

    ..我认为这是一个有趣的想法,所以我写了一个简单的实现:

    #!/usr/bin/env python2.6
    import re
    
    class SRE_Match_Wrapper:
        def __init__(self, match):
            self.match = match
    
        def __exit__(self, type, value, tb):
            pass
    
        def __enter__(self):
            return self.match
    
        def __getattr__(self, name):
            if name == "__exit__":
                return self.__exit__
            elif name == "__enter__":
                return self.__name__
            else:
                return getattr(self.match, name)
    
    def rematch(pattern, inp):
        matcher = re.compile(pattern)
        x = SRE_Match_Wrapper(matcher.match(inp))
        return x
        return match
    
    if __name__ == '__main__':
        # Example:
        with rematch("(\d+)g", "123g") as m:
            if m:
                print(m.group(1))
    
        with rematch("(\d+)g", "123") as m:
            if m:
                print(m.group(1))
    

    (理论上,此功能可以修补到 _sre.SRE_Match 对象)

    如果你能跳过执行,那就太好了 with 如果没有匹配项,则语句的代码块将简化为。。

    with rematch("(\d+)g", "123") as m:
        print(m.group(1)) # only executed if the match occurred
    

    ..但根据我的推断,这似乎是不可能的 PEP 343

    10 回复  |  直到 7 年前
        1
  •  12
  •   Glenn Maynard    17 年前

    我不认为这是微不足道的。如果我经常写这样的代码,我不想在代码周围撒上多余的条件句。

    import re
    
    def rematch(pattern, inp):
        matcher = re.compile(pattern)
        matches = matcher.match(inp)
        if matches:
            yield matches
    
    if __name__ == '__main__':
        for m in rematch("(\d+)g", "123g"):
            print(m.group(1))
    

    奇怪的是,它使用迭代器来处理不迭代的东西——它更接近于条件,乍一看,它可能会为每个匹配产生多个结果。

    上下文管理器不能完全跳过其托管功能,这似乎很奇怪;虽然这不是“with”的明确用例之一,但它似乎是一个自然的扩展。

        2
  •  4
  •   mhubig    13 年前

    开始 Python 3.8 assignment expressions (PEP 572) ( := 运算符),我们现在可以捕获条件值 re.match(r'(\d+)g', '123g') match 以便两者都检查是否 None 然后在病症体内重复使用:

    >>> if match := re.match(r'(\d+)g', '123g'):
    ...   print(match.group(1))
    ... 
    123
    >>> if match := re.match(r'(\d+)g', 'dddf'):
    ...   print(match.group(1))
    ...
    >>>
    
        3
  •  1
  •   AMADANON Inc.    12 年前

    另一个不错的语法是这样的:

    header = re.compile('(.*?) = (.*?)$')
    footer = re.compile('(.*?): (.*?)$')
    
    if header.match(line) as m:
        key, value = m.group(1,2)
    elif footer.match(line) as m
        key, value = m.group(1,2)
    else:
        key, value = None, None
    
        4
  •  0
  •   Glenn Maynard    17 年前

    基于格伦·梅纳德的解决方案,我有另一种方法:

    for match in [m for m in [re.match(pattern,key)] if m]:
        print "It matched: %s" % match
    

    与Glen的解决方案类似,这要么是0次(如果没有匹配),要么是1次(如果匹配)。

    不需要子,但结果不太整洁。

        5
  •  0
  •   Blixt    17 年前

    如果你在一个地方做了很多这样的事情,这里有一个替代答案:

    import re
    class Matcher(object):
        def __init__(self):
            self.matches = None
        def set(self, matches):
            self.matches = matches
        def __getattr__(self, name):
            return getattr(self.matches, name)
    
    class re2(object):
        def __init__(self, expr):
            self.re = re.compile(expr)
    
        def match(self, matcher, s):
            matches = self.re.match(s)
            matcher.set(matches)
            return matches
    
    pattern = re2("(\d+)g")
    m = Matcher()
    if pattern.match(m, "123g"):
        print(m.group(1))
    if not pattern.match(m, "x123g"):
        print "no match"
    

        6
  •  0
  •   etuardu    14 年前

    我不认为使用 with 是这种情况下的解决方案。你必须在 BLOCK 部件(由用户指定)并具有 __exit__ 方法返回 True “吞下”例外。所以它永远不会看起来很好。

    我建议使用类似于Perl语法的语法。让你自己的扩展 re 模块(我称之为 rex )并在其模块命名空间中设置变量:

    if rex.match('(\d+)g', '123g'):
        print rex._1
    

    正如您在下面的评论中看到的,此方法既不是范围安全的,也不是线程安全的。只有当你完全确定你的应用程序将来不会变成多线程的,并且从你使用它的作用域调用的任何函数都会被调用时,你才会使用它 使用相同的方法。

        7
  •  0
  •   oneself    14 年前

    这看起来并不漂亮,但你可以从中获利 getattr(object, name[, default])

    >>> getattr(re.match("(\d+)g", "123g"), 'group', lambda n:'')(1)
    '123'
    >>> getattr(re.match("(\d+)g", "X23g"), 'group', lambda n:'')(1)
    ''
    

    模仿 如果匹配打印组 flow,你可以(ab)使用 for 这样表述:

    >>> for group in filter(None, [getattr(re.match("(\d+)g", "123g"), 'group', None)]):
            print(group(1))
    123
    >>> for group in filter(None, [getattr(re.match("(\d+)g", "X23g"), 'group', None)]):
            print(group(1))
    >>> 
    

    当然,你可以定义一个小函数来做脏活:

    >>> matchgroup = lambda p,s: filter(None, [getattr(re.match(p, s), 'group', None)])
    >>> for group in matchgroup("(\d+)g", "123g"):
            print(group(1))
    123
    >>> for group in matchgroup("(\d+)g", "X23g"):
            print(group(1))
    >>> 
    
        8
  •  0
  •   dennis    11 年前

    这不是完美的解决方案,但确实允许您为同一str链接多个匹配选项:

    class MatchWrapper(object):
      def __init__(self):
        self._matcher = None
    
      def wrap(self, matcher):
        self._matcher = matcher
    
      def __getattr__(self, attr):
        return getattr(self._matcher, attr)
    
    def match(pattern, s, matcher):
      m = re.match(pattern, s)
      if m:
        matcher.wrap(m)
        return True
      else:
        return False
    
    matcher = MatchWrapper()
    s = "123g";
    if _match("(\d+)g", line, matcher):
      print matcher.group(1)
    elif _match("(\w+)g", line, matcher):
      print matcher.group(1)
    else:
      print "no match"
    
        9
  •  0
  •   Rhubbarb    11 年前

    以下是我的解决方案:

    import re
    
    s = 'hello world'
    
    match = []
    if match.append(re.match('w\w+', s)) or any(match):
        print('W:', match.pop().group(0))
    elif match.append(re.match('h\w+', s)) or any(match):
        print('H:', match.pop().group(0))
    else:
        print('No match found')
    

    否则如果

    import re
    
    s = 'hello world'
    
    if vars().update(match=re.match('w\w+', s)) or match:
        print('W:', match.group(0))
    elif vars().update(match=re.match('h\w+', s)) or match:
        print('H:', match.group(0))
    else:
        print('No match found')
    

    两者 追加 更新 返回 。因此,您必须使用 在每种情况下的一部分。