`match = re.match(); if match: ...` 的替代方案?

35 投票
10 回答
23934 浏览
提问于 2025-04-15 13:01

如果你想检查某个东西是否符合正则表达式,如果符合,就打印出第一个匹配的部分,你可以这样做:

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
}

来自 这个 Reddit 评论

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 个回答

3

还有一种不错的写法可以是这样的:

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
12

我觉得这并不简单。如果我经常写这样的代码,我可不想到处加一些多余的条件判断。

这有点奇怪,但你可以用一个迭代器来实现:

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”语句的明确用法,但看起来像是一个很自然的扩展。

5

Python 3.8 开始,引入了 赋值表达式 (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))
...
>>>

撰写回答