Python 提取模式匹配

Posted

技术标签:

【中文标题】Python 提取模式匹配【英文标题】:Python extract pattern matches 【发布时间】:2013-02-26 17:56:16 【问题描述】:

Python 2.7.1 我正在尝试使用 python 正则表达式来提取模式中的单词

我有一些看起来像这样的字符串

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?

【问题讨论】:

【参考方案1】:

您需要从正则表达式中捕获。 search 用于模式,如果找到,则使用 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'

【讨论】:

你确定第一场比赛不是group(0)吗? 有点晚了,但是是和不是。 group(0) 返回匹配的文本,而不是第一个捕获组。代码注释是正确的,而您似乎混淆了捕获组和匹配项。 group(1) 返回第一个捕获组。 这类问题应该强制重写文档【参考方案2】:

您可以使用匹配组:

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

例如

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

如 cmets 中所述,您可能希望使您的正则表达式不贪婪:

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

只拾取'name ' 和下一个' is valid' 之间的内容(而不是让您的正则表达式拾取您组中的其他' is valid'

【讨论】:

可能需要非贪婪匹配...(除非用户名可以是多个单词...) @JonClements -- 你的意思是(.*?)?是的,这是可能的,尽管没有必要,除非我们使用re.DOTALL 是的 - re.findall('name (.*) is valid', 'name jon clements is valid is valid is valid') 可能不会产生预期的结果... 这不适用于 Python 2.7.1?它只是打印一个模式对象? @CalmStorm -- 哪个部分不起作用(我在 python2.7.3 上测试过)?我使用.group的部分与您接受的答案完全相同...【参考方案3】:

你可以这样使用:

import re
s = #that big string
# the parenthesis create a group with what was matched
# and '\w' matches only alphanumeric charactes
p = re.compile("name +(\w+) +is valid", re.flags)
# use search(), so the match doesn't have to happen 
# at the beginning of "big string"
m = p.search(s)
# search() returns a Match object with information about what was matched
if m:
    name = m.group(1)
else:
    raise Exception('name not found')

【讨论】:

【参考方案4】:

也许这会更短更容易理解:

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'

【讨论】:

【参考方案5】:

您可以使用组(用'('')' 表示)来捕获部分字符串。然后匹配对象的group() 方法为您提供组的内容:

>>> import re
>>> s = 'name my_user_name is valid'
>>> match = re.search('name (.*) is valid', s)
>>> match.group(0)  # the entire match
'name my_user_name is valid'
>>> match.group(1)  # the first parenthesized subgroup
'my_user_name'

在 Python 3.6+ 中,您还可以将 index 放入匹配对象中,而不是使用 group()

>>> match[0]  # the entire match 
'name my_user_name is valid'
>>> match[1]  # the first parenthesized subgroup
'my_user_name'

【讨论】:

【参考方案6】:

你想要一个capture group。

p = re.compile("name (.*) is valid", re.flags) # parentheses for capture groups
print p.match(s).groups() # This gives you a tuple of your matches.

【讨论】:

【参考方案7】:

这是一种不使用组的方法(Python 3.6 或更高版本):

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

【讨论】:

这解决了 Python 正则表达式,但没有解决 OP 的具体问题。 此外,这基本上没有为提及 3.6+ 索引语法的现有答案添加任何新内容。【参考方案8】:

您还可以使用捕获组(?P&lt;user&gt;pattern) 并像字典match['user'] 一样访问该组。

string = '''someline abc\n
            someother line\n
            name my_user_name is valid\n
            some more lines\n'''

pattern = r'name (?P<user>.*) is valid'
matches = re.search(pattern, str(string), re.DOTALL)
print(matches['user'])

# my_user_name

【讨论】:

【参考方案9】:

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

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

【讨论】:

【参考方案10】:

看起来您实际上是在尝试提取名称,但只需找到匹配项即可。如果是这种情况,为您的匹配设置跨度索引会很有帮助,我建议使用re.finditer。作为快捷方式,您知道正则表达式的 name 部分的长度为 5,is valid 的长度为 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)

【讨论】:

以上是关于Python 提取模式匹配的主要内容,如果未能解决你的问题,请参考以下文章

在文本字符串中搜索模式,然后提取匹配的模式

python提取指定字符中间的内容?

如何从pyspark中的文件中匹配/提取多行模式

Pandas 从第二个数据帧动态模式匹配并提取字符串

模式匹配算法:扫描+特征比较

图像处理基于形状提取和模式匹配组合的面部特征点提取方法(Matlab代码实现)