Regex и последовательность шаблонов? - PullRequest
4 голосов
/ 27 июня 2009

Есть ли способ сопоставить шаблон (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 ]

5 голосов
/ 27 июня 2009

Сделайте это в два шага, один, чтобы найти все числа, затем один, чтобы разделить их:

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']
1 голос
/ 28 июня 2009

не группирующие скобки: (?: 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)
1 голос
/ 27 июня 2009

Количество захваченных групп равно числу групп в скобках. Посмотрите на findall или finditer для решения вашей проблемы.

0 голосов
/ 28 июня 2009

Может быть, что-то подобное?

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'])
0 голосов
/ 28 июня 2009

Подумав о проблеме, думаю, у меня есть более простое решение с использованием именованных групп.

Самое простое регулярное выражение, которое может использовать пользователь (или я):

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

Класс синтаксического анализа имени файла примет первую группу в качестве имени шоу, вторую - номер сезона, третью - номер эпизода. Это охватывает большинство файлов.

Я разрешу несколько разных именованных групп для них:

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

Для поддержки нескольких эпизодов я буду поддерживать две именованные группы, например, startingepisodenumber и endingepisodenumber для поддержки таких вещей, как showname.s01e01-03:

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

И, наконец, разрешить именованные группы с именами, соответствующими episodenumber\d+ (episodenumber1, episodenumber2 и т. Д.):

(?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 в одном регулярном выражении - если кто-то решит это!)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...