Python 正则表达式查找连字符后非数字范围的匹配组,如果范围不存在则忽略模式的其余部分
Python Regex Find match group of range of non digits after hyphen and if range is not present ignore rest of pattern
我对更高级的正则表达式概念比较陌生,开始研究后视和前视,但我感到困惑,需要一些指导。我有一个场景,我可能有几个不同类型的发布 zip,名称如下:
v1.1.2-beta.2.zip
v1.1.2.zip
我想写一个可以在两种类型中找到匹配组的单行正则表达式。例如,如果文件类型是第一个 zip,我想要三个匹配组,如下所示:
v1.1.2-beta.2.zip
Group 1: v1.1.2
Group 2: beta
Group 3. 2
或者如果第二个 zip one 匹配组:
v1.1.2.zip
Group 1: v1.1.2
这是我开始感到困惑的地方,因为我假设正则表达式需要断言连字符是否存在,如果不存在,则只查找一个匹配组,如果找不到其他 3 个。
(v[0-9.]{0,}).([A-Za-z]{0,}).([0-9]).zip
这是我写的初始正则表达式 成功匹配第一种类型但没有条件。我正在考虑做一些事情,比如匹配连字符后的非数字组范围,但不能完全让它工作,也不知道让它忽略模式的其余部分,如果不接受,只接受第一组找到连字符
([\D]{0,}(?=[-]) # Does not work
有人能给我指出正确的方向吗?
我们可以使用下面的正则表达式:
(v\d+(?:\.\d+)*)(?:[-]([A-Za-z]+))?((?:\.\d+)*)\.zip
这会产生三组:第一组是版本,第二组是可选的:破折号 -
后跟字母字符,然后是可选的点序列,后跟数字,最后是 .zip
.
如果我们忽略 \.zip
后缀(好吧,我认为这是相当微不足道的),那么仍然有三组:
(v\d+(?:\.\d+)*)
:以 v
开头后跟 \d+
(一个或多个数字)的正则表达式组。然后我们有一个 non-capture 组(一个以 (?:..)
开头的组捕获 \.\d+
一个点后跟一个或多个数字的序列。我们重复这样子组零次或多次。
(?:[-]([A-Za-z]+))?
:一个以连字符 [-]
开头,然后是一个或多个 [A-Za-z]
字符的捕获组。然而,捕获组是可选的(末尾的 ?
)。
((?:\.\d+)*)
: 一个组又具有这样的 \.\d+
非捕获子组,所以我们捕获一个点后跟一串数字,并且此模式重复零次或多次。
例如:
rgx = re.compile(r'(v\d+(?:\.\d+)*)([-][A-Za-z]+)?((?:\.\d+)*)\.zip')
然后我们得到:
>>> rgx.findall('v1.1.2-beta.2.zip')
[('v1.1.2', '-beta', '.2')]
>>> rgx.findall('v1.1.2.zip')
[('v1.1.2', '', '')]
您可以使用 re.findall
:
import re
s = ['v1.1.2-beta.2.zip', 'v1.1.2.zip']
final_results = [re.findall('[a-zA-Z]{1}[\d\.]+|(?<=\-)[a-zA-Z]+|\d+(?=\.zip)', i) for i in s]
groupings = ["{}\n{}".format(a, '\n'.join(f'Group {i}: {c}' for i, c in enumerate(b, 1))) for a, b in zip(s, final_results)]
for i in groupings:
print(i)
print('-'*10)
输出:
v1.1.2-beta.2.zip
Group 1: v1.1.2
Group 2: beta
Group 3: 2
----------
v1.1.2.zip
Group 1: v1.1.2.
----------
请注意,从 re.findall
获得的结果是:
[['v1.1.2', 'beta', '2'], ['v1.1.2.']]
下面是我将如何使用 re.search
来解决这个问题。请注意,我们在这里不需要环顾四周;只需一个相当复杂的模式就可以完成这项工作。
import re
regex = r"(v\d+(?:\.\d+)*)(?:-(\w+)\.(\d+))?\.zip"
str1 = "v1.1.2-beta.2.zip"
str2 = "v1.1.2.zip"
match = re.search(regex, str1)
print(match.group(1))
print(match.group(2))
print(match.group(3))
print("\n")
match = re.search(regex, str2)
print(match.group(1))
v1.1.2
beta
2
v1.1.2
如果您没有大量使用正则表达式的经验,提供每个步骤的解释可能不会让您加快速度。不过,我会评论一些括号中出现的 ?:
的使用。在这种情况下,?:
告诉正则表达式引擎 not 捕获里面的内容。我们这样做是因为您只想捕获(最多)三个特定的东西。
我对更高级的正则表达式概念比较陌生,开始研究后视和前视,但我感到困惑,需要一些指导。我有一个场景,我可能有几个不同类型的发布 zip,名称如下:
v1.1.2-beta.2.zip
v1.1.2.zip
我想写一个可以在两种类型中找到匹配组的单行正则表达式。例如,如果文件类型是第一个 zip,我想要三个匹配组,如下所示:
v1.1.2-beta.2.zip
Group 1: v1.1.2
Group 2: beta
Group 3. 2
或者如果第二个 zip one 匹配组:
v1.1.2.zip
Group 1: v1.1.2
这是我开始感到困惑的地方,因为我假设正则表达式需要断言连字符是否存在,如果不存在,则只查找一个匹配组,如果找不到其他 3 个。
(v[0-9.]{0,}).([A-Za-z]{0,}).([0-9]).zip
这是我写的初始正则表达式 成功匹配第一种类型但没有条件。我正在考虑做一些事情,比如匹配连字符后的非数字组范围,但不能完全让它工作,也不知道让它忽略模式的其余部分,如果不接受,只接受第一组找到连字符
([\D]{0,}(?=[-]) # Does not work
有人能给我指出正确的方向吗?
我们可以使用下面的正则表达式:
(v\d+(?:\.\d+)*)(?:[-]([A-Za-z]+))?((?:\.\d+)*)\.zip
这会产生三组:第一组是版本,第二组是可选的:破折号 -
后跟字母字符,然后是可选的点序列,后跟数字,最后是 .zip
.
如果我们忽略 \.zip
后缀(好吧,我认为这是相当微不足道的),那么仍然有三组:
(v\d+(?:\.\d+)*)
:以 v
开头后跟 \d+
(一个或多个数字)的正则表达式组。然后我们有一个 non-capture 组(一个以 (?:..)
开头的组捕获 \.\d+
一个点后跟一个或多个数字的序列。我们重复这样子组零次或多次。
(?:[-]([A-Za-z]+))?
:一个以连字符 [-]
开头,然后是一个或多个 [A-Za-z]
字符的捕获组。然而,捕获组是可选的(末尾的 ?
)。
((?:\.\d+)*)
: 一个组又具有这样的 \.\d+
非捕获子组,所以我们捕获一个点后跟一串数字,并且此模式重复零次或多次。
例如:
rgx = re.compile(r'(v\d+(?:\.\d+)*)([-][A-Za-z]+)?((?:\.\d+)*)\.zip')
然后我们得到:
>>> rgx.findall('v1.1.2-beta.2.zip')
[('v1.1.2', '-beta', '.2')]
>>> rgx.findall('v1.1.2.zip')
[('v1.1.2', '', '')]
您可以使用 re.findall
:
import re
s = ['v1.1.2-beta.2.zip', 'v1.1.2.zip']
final_results = [re.findall('[a-zA-Z]{1}[\d\.]+|(?<=\-)[a-zA-Z]+|\d+(?=\.zip)', i) for i in s]
groupings = ["{}\n{}".format(a, '\n'.join(f'Group {i}: {c}' for i, c in enumerate(b, 1))) for a, b in zip(s, final_results)]
for i in groupings:
print(i)
print('-'*10)
输出:
v1.1.2-beta.2.zip
Group 1: v1.1.2
Group 2: beta
Group 3: 2
----------
v1.1.2.zip
Group 1: v1.1.2.
----------
请注意,从 re.findall
获得的结果是:
[['v1.1.2', 'beta', '2'], ['v1.1.2.']]
下面是我将如何使用 re.search
来解决这个问题。请注意,我们在这里不需要环顾四周;只需一个相当复杂的模式就可以完成这项工作。
import re
regex = r"(v\d+(?:\.\d+)*)(?:-(\w+)\.(\d+))?\.zip"
str1 = "v1.1.2-beta.2.zip"
str2 = "v1.1.2.zip"
match = re.search(regex, str1)
print(match.group(1))
print(match.group(2))
print(match.group(3))
print("\n")
match = re.search(regex, str2)
print(match.group(1))
v1.1.2
beta
2
v1.1.2
如果您没有大量使用正则表达式的经验,提供每个步骤的解释可能不会让您加快速度。不过,我会评论一些括号中出现的 ?:
的使用。在这种情况下,?:
告诉正则表达式引擎 not 捕获里面的内容。我们这样做是因为您只想捕获(最多)三个特定的东西。