三个下划线分隔元素构成我的字符串: - 第一个(字母和数字) - 中间(字母,数字和下划线) - 最后(字母和数字)
最后一个元素是可选的。
注意:我需要按名字访问我的群组,而不是他们的索引。
示例:
String : abc_def
first : abc
middle : def
last : None
String : abc_def_xyz
first : abc
middle: def
last: xyz
String : abc_def_ghi_jkl_xyz
first : abc
middle : def_ghi_jkl
last : xyz
我找不到合适的正则表达式......
到目前为止,我有两个想法:
可选群组
(?P<first>[a-z]+)_(?P<middle>\w+)(_(?P<last>[a-z]+))?
但是中间组匹配到字符串结尾:
String : abc_def_ghi_jkl_xyz
first : abc
middle : def_ghi_jkl_xyz
last : vide
使用“|”
(?P<first>[a-z]+)_(?P<middle>\w+)_(?P<last>[a-z]+)|(?P<first>[a-z]+)_(?P<middle>\w+)
此表达式无效:第一组和中间组被声明两次。我虽然可以编写一个表达式来重用表达式第一部分中的匹配组:
(?P<first>[a-z]+)_(?P<middle>\w+)_(?P<last>[a-z]+)|(?P=first)_(?P=middle)
表达式有效,但是只有第一个和中间的字符串如abc_def不匹配。
注意
这些字符串实际上是我需要匹配的路径的一部分。可能是这样的路径:
任何想法只用正则表达式解决我的问题?对匹配的组进行后处理不是一种选择。
非常感谢!
答案 0 :(得分:4)
将中间组更改为非贪婪,并添加字符串开头和结尾锚点:
^(?P<first>[a-z]+)_(?P<middle>\w+?)(_(?P<last>[a-z]+))?$
默认情况下,\w+
将匹配为多,这会占用其余字符串。添加?
会使其匹配为 little 。
感谢Tim Pietzcker指出锚定要求。
答案 1 :(得分:1)
使用
^(?P<first>[a-z]+)_(?P<middle>\w+?)(_(?P<last>[a-z]+))?$
^
和$
将正则表达式锚定在字符串的开头和结尾。
使\w+?
懒惰允许它尽可能少地匹配(但至少有一个字符)。
编辑:
对于现在包含此字符串之前和之后的路径的已更改要求,此方法有效:
^(.*?/)(?P<first>[a-z]+)_(?P<middle>\w+?)(_(?P<last>[a-z]+))?(/.*)?$
代码示例(Python 3.1):
import re
paths = ["/my/path/to/abc_def",
"/my/path/to/abc_def/",
"/my/path/to/abc_def/some/other/stuf",
"/my/path/to/abc_def/some/other/stuf/",
"/my/path/to/abc_def_ghi_jkl_xyz",
"/my/path/to/abc_def_ghi_jkl_xyz/",
"/my/path/to/abc_def_ghi_jkl_xyz/some/other/stuf",
"/my/path/to/abc_def_ghi_jkl_xyz/some/other/stuf/"]
regex = re.compile(r"^(.*?/)(?P<first>[a-z]+)_(?P<middle>\w+?)(_(?P<last>[a-z]+))?(/.*)?$")
for path in paths:
match = regex.match(path)
print ("{}:\nBefore: {}\nFirst: {}\nMiddle: {}\nLast: {}\nAfter: {}\n".format(
path, match.group(1), match.group("first"), match.group("middle"),
match.group("last"), match.group(6)))
输出:
/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/
答案 2 :(得分:0)
试试这个正则表达式:
^(?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'}
答案 3 :(得分:0)
不需要那么复杂。
>>> 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
答案 4 :(得分:0)
感谢大家的帮助!我的问题的两个关键在哪里: - 在我的模式的末尾添加一个锚点 - 让中间人群不贪婪。
所以:
/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/
非常感谢你的帮助!