Python 提取模式匹配
- 2024-12-26 08:43:00
- admin 原创
- 104
问题描述:
我正在尝试使用正则表达式来提取模式内的单词。
我有一些像这样的字符串
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'
解决方案 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'
正如评论中提到的,您可能希望使您的正则表达式变得非贪婪:
p = re.compile('name (.*?) is valid')
只挑选'name '
和下一个之间的内容' is valid'
(而不是允许你的正则表达式挑选' is valid'
你的组中的其他内容)。
解决方案 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:
您可以使用组(用'('
和表示')'
)来捕获字符串的各个部分。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+ 中,您还可以索引匹配对象,而不是使用group()
:
>>> match[0] # the entire match
'name my_user_name is valid'
>>> match[1] # the first parenthesized subgroup
'my_user_name'
解决方案 5:
也许这个更简短并且更容易理解:
>>> 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'
解决方案 6:
您想要一个捕获组。
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('2ddd[01]d[0-3]d', 'report_20191207.xml')[0]
'20191207'
解决方案 8:
您还可以使用捕获组(?P<user>pattern)
并像字典一样访问该组match['user']
。
string = '''someline abc
someother line
name my_user_name is valid
some more lines
'''
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)
解决方案 11:
以下是问题的简单解决方案
import re
except_substring = "w+_w+_w+"
original_string = """someline abc
someother line
name my_user_name is valid
some more lines"""
m=re.findall(except_substring, original_string)
if m:
print(m[0]) #--> "my_user_name"
else:
print("Substring was not found")
或者我们可以创建以下函数:
def replace_all_exept_substring(original_string: str, except_substring: str) -> str:
"""
The function gets the substring to be skipped from the whole string
can get it in the form of a single word, e.g. "NoSuchUser"
or a regular expression, e.g. "Message.*has.been.*rejected."
original_string : the whole phrase to search for
except_substring : the phrase/word to be returned
return : the message sent to the following e mail address has been rejected
"""
m = re.findall(except_substring, original_string)
# A+1 if A > B else A-1
return m[0] if m else original_string
m=replace_all_exept_substring(original_string, except_substring)
print(m) #--> "my_user_name" or "original_string"