code-golf - `match = re.match(); if match: …` 习惯用法的替代?

  显示原文与译文双语对照的内容
0 0

如果你想检查是否有匹配的正规表达式,如果是,打印第一组。

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

这完全是 pedantic,但是中间 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中推断出

有什么想法就像我所说,这实在是个烦人的烦恼,几乎是code-golf的问题。

时间:原作者:12个回答

0 0

我觉得这不是无关紧要的。 如果我经常编写这样的代码,我不想在代码周围浪费多余的条件。

这有点奇怪,但你可以使用迭代器执行这里操作:

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))

奇怪的是它正在使用一个迭代器,它不是iterating--it更接近一个条件,乍看起来看起来它可能会为每个匹配产生多个结果。

上下文管理器不能导致它的托管函数被完全跳过,但这似乎不是"打开方式"的一个用例,它似乎是一个自然扩展。

原作者:
0 0

另一个不错的语法是:

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
原作者:
0 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"

可以编译的正规表达式 一旦与你相同的线程安全,创建一个可重用的匹配器对象为整个函数,然后你可以使用它非常简洁。 这也有好处,你可以扭转它明显way--to使用迭代器,你需要通过一个标志告诉其转化的结果。

它不是太多的帮助如果你只是做一个匹配每个函数,虽然,你不想让匹配器在比这更广泛的上下文对象;我萨德的blixt引起相同的问题解决方案。

原作者:
0 0

在这种情况下,我不认为使用 with 是解决方案。 你必须在 BLOCK 部件( 由用户指定的) 中引发一个异常,并让 __exit__ 方法返回 True 到"吞咽"。 所以它不会看起来很好。

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

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

就像你在下面的评论中看到的,这个方法既不是scope-也不是 thread-safe 。 你只会用这个如果你是完全确信你的应用程序将不会成为multi-threaded在未来,任何功能从你正在使用这个范围也使用相同的方法。

原作者:
0 0

这不是真正的pretty-looking,但是你可以从 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)
''

模仿如果匹配打印组流,( 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))
>>> 
原作者:
0 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"
原作者:
0 0

我还有另一种方法,基于maynard的Glen解决方案:

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

类似于glen的解决方案,这个itterates要么是 0 ( 如果没有匹配) 要么是 1 ( 如果匹配) 时间。

没有需要的子部件,但作为结果不太整洁。

原作者:
0 0

下面是我的解决方案:

import re
s = 'hello world'
match = []
if match.append(re.match('ww+', s)) or any(match):
 print('W:', match.pop().group(0))
elif match.append(re.match('hw+', 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('ww+', s)) or match:
 print('W:', match.group(0))
elif vars().update(match=re.match('hw+', s)) or match:
 print('H:', match.group(0))
else:
 print('No match found')

附加更新 没有返回。 所以,你必须在每个案例中使用磅或者 part的部分来实际检查表达式的结果。

不幸的是,只要代码驻留 top-level,换句话说,就不在函数中。

原作者:
0 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 。

原作者:
...