我试图使用正则表达式来提取模式内的单词。

我有一些像这样的弦

someline abc
someother line
name my_user_name is valid
some more lines

我想提取单词my_user_name。我这样做

import re
s = #that big string
p = re.compile("name .* is valid", re.flags)
p.match(s)  # this gives me <_sre.SRE_Match object at 0x026B6838>

我现在如何提取my_user_name ?


当前回答

也许这更简短,更容易理解:

import re
text = '... someline abc... someother line... name my_user_name is valid.. some more lines'
>>> re.search('name (.*) is valid', text).group(1)
'my_user_name'

其他回答

你可以使用匹配组:

p = re.compile('name (.*) is valid')

e.g.

>>> import re
>>> p = re.compile('name (.*) is valid')
>>> s = """
... someline abc
... someother line
... name my_user_name is valid
... some more lines"""
>>> p.findall(s)
['my_user_name']

这里我使用re.findall而不是re.search来获取my_user_name的所有实例。使用re.search,你需要从匹配对象的组中获取数据:

>>> p.search(s)   #gives a match object or None if no match is found
<_sre.SRE_Match object at 0xf5c60>
>>> p.search(s).group() #entire string that matched
'name my_user_name is valid'
>>> p.search(s).group(1) #first group that match in the string that matched
'my_user_name'

正如评论中提到的,你可能想让你的正则表达式是非贪婪的:

p = re.compile('name (.*?) is valid')

只取'name '和下一个' is valid'之间的东西(而不是让你的正则表达式取你组中的其他' is valid'。

这里有一种不使用组的方法(Python 3.6或以上):

>>> re.search('2\d\d\d[01]\d[0-3]\d', 'report_20191207.xml')[0]
'20191207'

我通过谷歌找到了这个答案,因为我想用多个组直接将re.search()结果解压缩到多个变量中。虽然这对某些人来说可能是显而易见的,但对我来说却不是,因为我过去总是使用group(),所以它可能会帮助那些未来也不知道group*s*()的人。

s = "2020:12:30"
year, month, day = re.search(r"(\d+):(\d+):(\d+)", s).groups()

您需要从正则表达式中捕获。搜索模式,如果找到,使用group(index)检索字符串。假设执行了有效的检查:

>>> p = re.compile("name (.*) is valid")
>>> result = p.search(s)
>>> result
<_sre.SRE_Match object at 0x10555e738>
>>> result.group(1)     # group(1) will return the 1st capture (stuff within the brackets).
                        # group(0) will returned the entire matched text.
'my_user_name'

看起来您实际上是在试图提取一个名称,而不是简单地查找一个匹配项。如果是这种情况,为匹配设置span索引是有帮助的,我建议使用re.finditer。作为一个快捷方式,您知道正则表达式的名称部分的长度为5,有效的长度为9,因此您可以对匹配的文本进行切片以提取名称。

注意:在你的例子中,s看起来像是带换行符的字符串,所以这就是下面的假设。

## covert s to list of strings separated by line: s2 = s.splitlines() ## find matches by line: for i, j in enumerate(s2): matches = re.finditer("name (.*) is valid", j) ## ignore lines without a match if matches: ## loop through match group elements for k in matches: ## get text match_txt = k.group(0) ## get line span match_span = k.span(0) ## extract username my_user_name = match_txt[5:-9] ## compare with original text print(f'Extracted Username: {my_user_name} - found on line {i}') print('Match Text:', match_txt)