Python正则表达式在连字符后查找非数字范围的匹配组,如果范围不存在,则忽略模式的其余部分

2024-04-26 18:11:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我对更高级的regex概念比较新,并且开始研究look behinds和lookaheads,但是我感到困惑,需要一些指导。我有一个场景,在这个场景中,我可能有几个不同类型的释放拉链,比如:

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

这是我编写的初始regex,它成功地匹配了第一种类型,但没有条件。我在考虑做一些事情,比如在连字符之后匹配非数字的组范围,但是不能很好地让它工作,并且不知道如何让它忽略模式的其余部分,如果没有找到连字符,就只接受第一个组

([\D]{0,}(?=[-]) # Does not work

有人能给我指出正确的方向吗?你知道吗


Tags: 概念类型场景groupzip字符事情regex
3条回答

您可以使用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

Demo

如果您对regex没有太多的经验,那么提供每个步骤的解释可能不会让您跟上进度。不过,我将对一些括号中出现的?:的用法进行评论。在这种情况下,?:告诉regex引擎而不是捕获内部内容。我们这样做是因为您只想捕获(最多)三个特定的内容。你知道吗

我们可以使用以下正则表达式:

(v\d+(?:\.\d+)*)(?:[-]([A-Za-z]+))?((?:\.\d+)*)\.zip

这样就产生了三个组:第一组是版本,第二组是可选的:破折号-后跟字母字符,然后是可选的点序列,后跟数字,最后是.zip。你知道吗

如果我们忽略了\.zip后缀(我假设这是很普通的),那么仍然有三个组:

(v\d+(?:\.\d+)*):以v开头,后跟\d+(一个或多个数字)的正则表达式组。然后我们有一个非捕获组(一个以(?:..)开始的组,它捕获\.\d+一个点,后跟一个或多个数字序列。我们重复这样的子组零次或多次。你知道吗

(?:[-]([A-Za-z]+))?:以连字符[-]开始,然后是一个或多个[A-Za-z]字符的捕获组。但是,capture组是可选的(末尾的?)。你知道吗

((?:\.\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', '', '')]

相关问题 更多 >