将捕获的组放在一行中

时间:2014-04-29 13:59:31

标签: python regex syntax

有一种已知的"模式"获取捕获的组值,如果不匹配则获取空字符串:

match = re.search('regex', 'text')
if match:
    value = match.group(1)
else:
    value = ""

或:

match = re.search('regex', 'text')
value = match.group(1) if match else ''

有一种简单的pythonic方法可以在一行中完成吗?

换句话说,如果没有找到捕获组,我可以提供默认值吗?


例如,我需要从_字符串后面的文本中提取所有字母数字字符(和key=):

>>> import re
>>> PATTERN = re.compile('key=(\w+)')
>>> def find_text(text):
...     match = PATTERN.search(text)
...     return match.group(1) if match else ''
... 
>>> find_text('foo=bar,key=value,beer=pub')
'value'
>>> find_text('no match here')
''

find_text()是否可以成为一个班轮?

这只是一个例子,我正在寻找一种通用方法。

9 个答案:

答案 0 :(得分:10)

引自MatchObjects docs

  

匹配对象的布尔值始终为True。由于match()search()在没有匹配项时返回None,您可以测试是否与简单的if语句匹配:

match = re.search(pattern, string)
if match:
   process(match)

由于没有其他选项,并且当您使用某个功能时,我想提供此替代选项

def find_text(text, matches = lambda x: x.group(1) if x else ''):
    return matches(PATTERN.search(text))

assert find_text('foo=bar,key=value,beer=pub') == 'value'
assert find_text('no match here') == ''

这是完全相同的,但只有你需要做的检查是默认参数化的。

在评论中考虑@ Kevin的解决方案和@ devnull的建议,你可以做这样的事情

def find_text(text):
    return next((item.group(1) for item in PATTERN.finditer(text)), "")

这利用了以下事实:next接受默认值作为参数返回。但这有在每次迭代时创建生成器表达式的开销。所以,我会坚持第一个版本。

答案 1 :(得分:4)

您可以使用模式,使用捕获组中字符串末尾的空替代项:

>>> re.search(r'((?<=key=)\w+|$)', 'foo=bar,key=value').group(1)
'value'
>>> re.search(r'((?<=key=)\w+|$)', 'no match here').group(1)
''

答案 2 :(得分:3)

可以在单个单行中引用函数调用的结果两次:创建一个lambda表达式并在参数中调用该函数。

value = (lambda match: match.group(1) if match else '')(re.search(regex,text))

但是,我并不认为这特别易读。负责任地编码 - 如果您要撰写棘手的代码,请留下描述性评论!

答案 3 :(得分:3)

Re:&#34;有一种简单的pythonic方法可以在一行中完成吗?&#34;答案是。任何让它在一行中工作的方法(没有定义你自己的包装器),阅读比你已经提出的方式更难听。但是定义自己的包装 完全是Pythonic,就像使用两条非常易读的行而不是一条难以阅读的行。

答案 4 :(得分:2)

单行版本:

if re.findall(pattern,string): pass

这里的问题是你想要准备多场比赛或确保你的模式只打一次。扩展版本:

# matches is a list
matches = re.findall(pattern,string)

# condition on the list fails when list is empty
if matches:
    pass

因此,对于您的示例,“在key = string”之后从文本中提取所有字母数字字符(和_):

# Returns 
def find_text(text):
    return re.findall("(?<=key=)[a-zA-Z0-9_]*",text)[0]

答案 5 :(得分:2)

一个衬垫,一个衬垫......为什么你不能在2行上写它?

getattr(re.search('regex', 'text'), 'group', lambda x: '')(1)

你的第二个解决方案,如果罚款。如果您愿意,可以从中创建一个功能。我的解决方案是出于演示目的,它绝不是pythonic。

答案 6 :(得分:2)

一条线,虽然不是Pythonic。

find_text = lambda text: (lambda m: m and m.group(1) or '')(PATTERN.search(text))

实际上,在Scheme编程语言中,所有局部变量构造都可以从lambda函数应用程序派生。

答案 7 :(得分:1)

你可以这样做:

value = re.search('regex', 'text').group(1) if re.search('regex', 'text') else ''

考虑到你运行正则表达式两次这一事实,它并不是非常有效。

或者@Kevin建议只运行一次:

value = (lambda match: match.group(1) if match else '')(re.search(regex,text))

答案 8 :(得分:1)

Python 3.8开始并引入assignment expressions (PEP 572):=运算符),我们可以命名正则表达式搜索表达式pattern.search(text),以便同时检查是否存在匹配项(因为pattern.search(text)返回Nonere.Match对象)并使用它来提取匹配的组:

# pattern = re.compile(r'key=(\w+)')
match.group(1) if (match := pattern.search('foo=bar,key=value,beer=pub')) else ''
# 'value'
match.group(1) if (match := pattern.search('no match here')) else ''
# ''