正则表达式与模式序列?

4 投票
5 回答
2525 浏览
提问于 2025-04-15 12:31

有没有办法把一个模式(e\d\d)匹配多次,并把每次匹配的结果放到一个组里?比如,给定这个字符串……

blah.s01e24e25

……我希望能得到四个组:

1 -> blah
2 -> 01
3 -> 24
4 -> 25

显而易见,使用的正则表达式是(在Python的正则表达式中):

import re
re.match("(\w+).s(\d+)e(\d+)e(\d+)", "blah.s01e24e25").groups()

……但我还想匹配以下任意一种情况:

blah.s01e24
blah.s01e24e25e26

你似乎不能直接用 (e\d\d)+,或者说可以,但它只会捕获最后一次出现的结果:

>>> re.match("(\w+).s(\d+)(e\d\d){2}", "blah.s01e24e25e26").groups()
('blah', '01', 'e25')
>>> re.match("(\w+).s(\d+)(e\d\d){3}", "blah.s01e24e25e26").groups()
('blah', '01', 'e26')

我想用一个正则表达式来完成这个,因为我有多个模式需要匹配电视节目文件名,不想重复每个表达式来处理多个剧集:

\w+\.s(\d+)\.e(\d+) # matches blah.s01e01
\w+\.s(\d+)\.e(\d+)\.e(\d+) # matches blah.s01e01e02
\w+\.s(\d+)\.e(\d+)\.e(\d+)\.e(\d+) # matches blah.s01e01e02e03

\w - \d+x\d+ # matches blah - 01x01
\w - \d+x\d+\d+ # matches blah - 01x01x02
\w - \d+x\d+\d+\d+ # matches blah - 01x01x02x03

……还有许多其他模式也是如此。

还有一个复杂的地方是——我希望把这些正则表达式存储在一个配置文件里,所以不想用多个正则表达式和函数调用的解决方案——但如果这真的不行,我就允许用户添加简单的正则表达式。

基本上,有没有办法用正则表达式捕获一个重复的模式?

5 个回答

1

捕获的组数量等于括号组的数量。可以看看 findallfinditer 来解决你的问题。

5

可以分两步来做,第一步是找出所有的数字,第二步是把它们分开:

import re

def get_pieces(s):
    # Error checking omitted!
    whole_match = re.search(r'\w+\.(s\d+(?:e\d+)+)', s)
    return re.findall(r'\d+', whole_match.group(1))

print get_pieces(r"blah.s01e01")
print get_pieces(r"blah.s01e01e02")
print get_pieces(r"blah.s01e01e02e03")

# prints:
# ['01', '01']
# ['01', '01', '02']
# ['01', '01', '02', '03']
0

经过思考这个问题,我觉得我有一个更简单的解决方案,就是使用命名组。

用户(或者我)可以使用的最简单的正则表达式是:

(\w+\).s(\d+)\.e(\d+)

这个文件名解析类会把第一个组当作节目名称,第二个组当作季号,第三个组当作集数。这可以覆盖大多数文件。

我会允许几个不同的命名组来处理这些:

(?P<showname>\w+\).s(?P<seasonnumber>\d+)\.e(?P<episodenumber>\d+)

为了支持多个集数,我会支持两个命名组,类似于 startingepisodenumberendingepisodenumber,这样可以处理像 showname.s01e01-03 这样的情况:

(?P<showname>\w+\)\.s(?P<seasonnumber>\d+)\.e(?P<startingepisodenumber>\d+)-(?P<endingepisodenumber>e\d+)

最后,还允许命名组的名称匹配 episodenumber\d+(比如 episodenumber1episodenumber2 等等):

(?P<showname>\w+\)\.
s(?P<seasonnumber>\d+)\.
e(?P<episodenumber1>\d+)
e(?P<episodenumber2>\d+)
e(?P<episodenumber3>\d+)

这仍然可能需要为不同数量的 e01 重复模式,但不会有文件包含两个不连续的集数(比如 show.s01e01e03e04),所以使用 starting/endingepisodenumber 组应该能解决这个问题。对于用户遇到的奇怪情况,他们可以使用 episodenumber\d+ 的组名。

这并没有真正回答模式顺序的问题,但解决了我提出这个问题的原因!(如果有人能找到一个正则表达式来匹配 s01e23e24...e27,我仍然会接受这个答案!)

撰写回答