Python 查找正则表达式中的最后一个组

Python 查找正则表达式中的最后一个组,python,regex,Python,Regex,三个下划线分隔的元素构成我的字符串: -第一(字母和数字) -中间(字母、数字和下划线) -最后(字母和数字) 最后一个元素是可选的 注意:我需要按组名而不是索引访问组 示例: String : abc_def first : abc middle : def last : None 我找不到合适的正则表达式 到目前为止,我有两个想法: 可选组 (?P<first>[a-z]+)_(?P<middle>\w+)(_(?P<last>[a-z]+))?

三个下划线分隔的元素构成我的字符串: -第一(字母和数字) -中间(字母、数字和下划线) -最后(字母和数字)

最后一个元素是可选的

注意:我需要按组名而不是索引访问组

示例:

String : abc_def
first : abc
middle : def
last : None


我找不到合适的正则表达式

到目前为止,我有两个想法:

可选组

(?P<first>[a-z]+)_(?P<middle>\w+)(_(?P<last>[a-z]+))?
使用“|”键

(?P<first>[a-z]+)_(?P<middle>\w+)_(?P<last>[a-z]+)|(?P<first>[a-z]+)_(?P<middle>\w+)
(?P[a-z]+)(?P\w+)(?P[a-z]+)|(?P[a-z]+)(?P\w+)
此表达式无效:第一组和中间组声明了两次。我想我可以使用表达式第一部分中的匹配组编写一个表达式:

(?P<first>[a-z]+)_(?P<middle>\w+)_(?P<last>[a-z]+)|(?P=first)_(?P=middle)
(?P[a-z]+)(?P\w+)(?P[a-z]+)|(?P=first)(?P=middle)
表达式是有效的,但是只有第一个和中间的字符串(如abc_def)不匹配

注意

这些字符串实际上是我需要匹配的路径的一部分。它可以是如下路径:

  • /我的/path/to/abcdef
  • /我的/path/to/abcdef/
  • /我的/path/to/abc_def/some/other/stuf
  • /我的/path/to/abc_def/some/other/stuf/
  • /我的/path/to/abc_def_ghi_jkl_xyz
  • /我的/path/to/abc_def_ghi_jkl_xyz/
  • /我的/path/to/abc_def_ghi_jkl_xyz/some/other/stuf
  • /我的/path/to/abc_def_ghi_jkl_xyz/some/other/stuf/
有没有办法只用正则表达式来解决我的问题?不能对匹配的组进行后期处理


多谢各位

将中间组更改为非贪婪,并添加字符串起始和结束锚定:

^(?P<first>[a-z]+)_(?P<middle>\w+?)(_(?P<last>[a-z]+))?$
^(?P[a-z]+)(?P\w+)((?P[a-z]+)$
默认情况下,
\w+
将尽可能匹配,这将吃掉字符串的其余部分。添加
会告诉它尽可能少地匹配


感谢Tim Pietzcker指出锚定要求。

将中间组更改为非贪婪组,并添加字符串锚定的开头和结尾:

^(?P<first>[a-z]+)_(?P<middle>\w+?)(_(?P<last>[a-z]+))?$
^(?P[a-z]+)(?P\w+)((?P[a-z]+)$
默认情况下,
\w+
将尽可能匹配,这将吃掉字符串的其余部分。添加
会告诉它尽可能少地匹配

感谢Tim Pietzcker指出锚定要求。

使用

^(?P<first>[a-z]+)_(?P<middle>\w+?)(_(?P<last>[a-z]+))?$
代码示例(Python 3.1):

使用

代码示例(Python 3.1):


请尝试以下正则表达式:

^(?P<first>[a-z]+)_(?P<middle>[a-z]+(?:_[a-z]+)*?)(?:_(?P<last>[a-z]+))?$

请尝试以下正则表达式:

^(?P<first>[a-z]+)_(?P<middle>[a-z]+(?:_[a-z]+)*?)(?:_(?P<last>[a-z]+))?$

没必要那么复杂

>>> s="abc_def_ghi_jkl_xyz"
>>> s.rsplit("_",1)
>>> splitted=s.split("_")
>>> first=splitted[0]
>>> last=splitted[-1]
>>> middle=splitted[1:-1]
>>> middle='_'.join(splitted[1:-1])
>>> print middle
def_ghi_jkl

没必要那么复杂

>>> s="abc_def_ghi_jkl_xyz"
>>> s.rsplit("_",1)
>>> splitted=s.split("_")
>>> first=splitted[0]
>>> last=splitted[-1]
>>> middle=splitted[1:-1]
>>> middle='_'.join(splitted[1:-1])
>>> print middle
def_ghi_jkl

谢谢大家的帮助!我的问题的两个关键在于: -在我的模式末尾添加锚点 -使中间群体不贪婪

因此:


非常感谢你的帮助

谢谢大家的帮助!我的问题的两个关键在于: -在我的模式末尾添加锚点 -使中间群体不贪婪

因此:


非常感谢你的帮助

没有锚,这是行不通的。在
abc_def_ghi_jkl_xyz
中,
第一个
将匹配
abc
中间的
将匹配
d
最后一个
将为空。如果没有锚,这将无法工作。在
abc_def_ghi_jkl_xyz
中,
first
将匹配
abc
middle
将匹配
d
last
将为空。我应该添加的字符串实际上是更大字符串的一部分,因此我不能真正使用$anchor。我现在正在更新主要问题。@Charles:好吧,你可以用
/
(?:/$)
而不是
^
$
。我应该加上我的字符串实际上是更大字符串的一部分,所以我不能真正使用$anchor。我现在正在更新主要问题。@Charles:好吧,你可以用
/
(?:/$)
代替
^
$
/my/path/to/
是常量还是变量?如果是变量,您如何知道路径的哪个部分包含您试图从中提取子字符串的字符串?是常量还是变量?如果是变量,您如何知道路径的哪一部分包含您试图从中提取子字符串的字符串?我的问题是一个更大、大量正则表达式问题的一小部分。不管怎样,谢谢你的回答。由于第二条语句中的middle已经写过了(>>>middle=splitted[1:-1]>>>middle='''.''.join(splitted[1:-1]),middle=splitted[1:-1]),所以不需要了。我的问题是一个更大、更重正则表达式问题的一小部分。不管怎样,谢谢你的回答。由于第二条语句中的middle已经写过了(>>>middle=splitted[1:-1]>>>middle='''.''.join(splitted[1:-1]),因此不需要middle=splitted[1:-1])。
/my/path/to/abc_def:
Before: /my/path/to/
First: abc
Middle: def
Last: None
After: None

/my/path/to/abc_def/:
Before: /my/path/to/
First: abc
Middle: def
Last: None
After: /

/my/path/to/abc_def/some/other/stuf:
Before: /my/path/to/
First: abc
Middle: def
Last: None
After: /some/other/stuf

/my/path/to/abc_def/some/other/stuf/:
Before: /my/path/to/
First: abc
Middle: def
Last: None
After: /some/other/stuf/

/my/path/to/abc_def_ghi_jkl_xyz:
Before: /my/path/to/
First: abc
Middle: def_ghi_jkl
Last: xyz
After: None

/my/path/to/abc_def_ghi_jkl_xyz/:
Before: /my/path/to/
First: abc
Middle: def_ghi_jkl
Last: xyz
After: /

/my/path/to/abc_def_ghi_jkl_xyz/some/other/stuf:
Before: /my/path/to/
First: abc
Middle: def_ghi_jkl
Last: xyz
After: /some/other/stuf

/my/path/to/abc_def_ghi_jkl_xyz/some/other/stuf/:
Before: /my/path/to/
First: abc
Middle: def_ghi_jkl
Last: xyz
After: /some/other/stuf/
^(?P<first>[a-z]+)_(?P<middle>[a-z]+(?:_[a-z]+)*?)(?:_(?P<last>[a-z]+))?$
import re

strings = ['abc_def', 'abc_def_xyz', 'abc_def_ghi_jkl_xyz']
pattern = '^(?P<first>[a-z]+)_(?P<middle>[a-z]+(?:_[a-z]+)*?)(?:_(?P<last>[a-z]+))?$'
for string in strings:
    m = re.match(pattern, string)
    print m.groupdict()
{'middle': 'def', 'last': None, 'first': 'abc'}
{'middle': 'def', 'last': 'xyz', 'first': 'abc'}
{'middle': 'def_ghi_jkl', 'last': 'xyz', 'first': 'abc'}
>>> s="abc_def_ghi_jkl_xyz"
>>> s.rsplit("_",1)
>>> splitted=s.split("_")
>>> first=splitted[0]
>>> last=splitted[-1]
>>> middle=splitted[1:-1]
>>> middle='_'.join(splitted[1:-1])
>>> print middle
def_ghi_jkl
/start/of/the/path/(?P<a>[a-z]+)_(?P<b>\w+?)(_(?P<c>[a-z]+))?(/|$)
/jobs/ads/abc_J123/previs/m_name
/jobs/ads/abc_J123/previs/m_name/
/jobs/ads/abc_J123/previs/m_name/some_stuff
/jobs/ads/abc_J123/previs/m_name/some_stuff/
/jobs/ads/abc_J123/previs/m_name/some_stuff/other_stuff
/jobs/ads/abc_J123/previs/m_name/some_stuff/other_stuff/
/jobs/ads/abc_J123/previs/m_name_stage
/jobs/ads/abc_J123/previs/m_name_stage/
/jobs/ads/abc_J123/previs/m_name_stage/some_stuff
/jobs/ads/abc_J123/previs/m_name_stage/some_stuff/
/jobs/ads/abc_J123/previs/m_name_stage/some_stuff/other_stuff
/jobs/ads/abc_J123/previs/m_name_stage/some_stuff/other_stuff/
/jobs/ads/abc_J123/previs/m_long_name_stage
/jobs/ads/abc_J123/previs/m_long_name_stage/
/jobs/ads/abc_J123/previs/m_long_name_stage/some_stuff
/jobs/ads/abc_J123/previs/m_long_name_stage/some_stuff/
/jobs/ads/abc_J123/previs/m_long_name_stage/some_stuff/other_stuff
/jobs/ads/abc_J123/previs/m_long_name_stage/some_stuff/other_stuff/