如果你想检查某些东西是否与正则表达式相匹配,如果是,打印第一组,就可以了..
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
}
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
推断出的内容,这似乎是不可能的有什么想法吗?正如我所说,这实际上是微不足道的烦恼,几乎到了代码高尔夫......
答案 0 :(得分: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”的用例之一,但它似乎是一种自然延伸。
答案 1 :(得分:4)
另一个很好的语法是这样的:
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
答案 2 :(得分:2)
从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)
基于Glen Maynard的解决方案,我有另一种方法:
for match in [m for m in [re.match(pattern,key)] if m]:
print "It matched: %s" % match
与Glen的解决方案类似,它会改为0(如果不匹配)或1(如果匹配)次。
不需要子,但结果不那么整洁。
答案 4 :(得分:0)
我不认为在这种情况下使用with
是解决方案。您必须在BLOCK
部分(由用户指定)中引发异常,并让__exit__
方法返回True
以“吞下”异常。所以它永远不会好看。
我建议使用类似于Perl语法的语法。制作你自己的扩展re
模块(我称之为rex
)并让它在模块命名空间中设置变量:
if rex.match('(\d+)g', '123g'):
print rex._1
正如您在下面的评论中所看到的,此方法既不是范围也不是线程安全的。如果你完全确定你的应用程序将来不会变成多线程,那么你只会使用它,并且从你使用它的范围调用的任何函数也使用相同的函数方法
答案 5 :(得分:0)
如果你在一个地方做了很多这样的话,这里有另一个答案:
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"
您可以使用与re相同的线程安全性编译一次正则表达式,为整个函数创建单个可重用的Matcher对象,然后您可以非常简洁地使用它。这也有一个好处,你可以用显而易见的方式反转它 - 用迭代器做这个,你需要传递一个标志来告诉它反转它的结果。
如果你只为每个功能进行一次匹配,那就没什么用了;您不希望将Matcher对象保留在比这更广泛的上下文中;它会导致与Blixt解决方案相同的问题。
答案 6 :(得分:0)
这看起来并不漂亮,但您可以使用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)
''
要模仿 if match print group 流程,您可以(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))
>>>
答案 7 :(得分:0)
不是完美的解决方案,但允许您为同一个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"
答案 8 :(得分:0)
这是我的解决方案:
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')
您可以根据需要使用尽可能多的 elif 子句。
更好:
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')
附加和更新都会返回无。因此,您必须在每种情况下使用或部分来实际检查表达式的结果。
不幸的是,只有代码驻留在顶层,即不在函数中,这才有效。
答案 9 :(得分:0)
这就是我的所作所为:
def re_match_cond (match_ref, regex, text):
match = regex.match (text)
del match_ref[:]
match_ref.append (match)
return match
if __name__ == '__main__':
match_ref = []
if re_match_cond (match_ref, regex_1, text):
match = match_ref[0]
### ...
elif re_match_cond (match_ref, regex_2, text):
match = match_ref[0]
### ...
elif re_match_cond (match_ref, regex_3, text):
match = match_ref[0]
### ...
else:
### no match
### ...
也就是说,我将一个列表传递给函数以模拟pass-by-reference。