4

有没有办法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

..等等许多其他模式。

另一件使事情复杂化的事情 - 我希望将这些正则表达式存储在配置文件中,因此不需要使用多个正则表达式和函数调用的解决方案 - 但如果这被证明是不可能的,我将只允许用户添加简单的正则表达式

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

4

5 回答 5

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']
于 2009-06-27T19:53:39.053 回答
1

捕获组的数量等于括号组的数量。查看findallfinditer解决您的问题。

于 2009-06-27T19:56:18.657 回答
1

非分组括号: (?:asdfasdg)

哪些不必出现:(?:adsfasdf)?

c = re.compile(r"""(\w+).s(\d+)
                       (?:
                            e(\d+)
                            (?:
                                  e(\d+)
                            )?
                        )?
               """, re.X)

或者

c = re.compile(r"""(\w+).s(\d+)(?:e(\d+)(?:e(\d+))?)?""", re.X)
于 2009-06-27T20:18:27.707 回答
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+)

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

这并不能真正回答模式序列问题,但它解决了导致我问它的问题!(我仍然会接受另一个显示如何s01e23e24...e27在一个正则表达式中匹配的答案 - 如果有人解决了这个问题!)

于 2009-06-27T20:32:22.000 回答
0

也许是这样的?

def episode_matcher(filename):
    m1= re.match(r"(?i)(.*?)\.s(\d+)((?:e\d+)+)", filename)
    if m1:
        m2= re.findall(r"\d+", m1.group(3))
        return m1.group(1), m1.group(2), m2
    # auto return None here

>>> episode_matcher("blah.s01e02")
('blah', '01', ['02'])
>>> episode_matcher("blah.S01e02E03")
('blah', '01', ['02', '03'])
于 2009-06-28T01:11:38.927 回答