Многочисленные шаблоны регулярных выражений Python, извлечение правильных групп

Я написал регулярное выражение на Python, которое должно искать сезоны и эпизоды, следующие за числом. Как вы можете видеть в моем коде, у меня есть поддержка всех видов шаблонов, которые ищут то, что я хочу.

import re

episode = re.compile(r"""(?:s|season)(?:\s)(\d+)(?:e|x|episode|\n)(?:\s)(\d+)| # s 01e 02
                        (?:s|season)(\d+)(?:e|x|episode|\n)(?:\s)(\d+)| # s01e 02
                        (?:s|season)(?:\s)(\d+)(?:e|x|episode|\n)(\d+)| # s 01e02
                        (?:s|season)(\d+)(?:e|x|episode|\n)(\d+)| # s01e02
                        (?:s|season)(\d+)(?:.*)(?:e|x|episode|\n)(\d+)| # s01 random123 e02
                        (?:s|season)(?:\s)(\d+)(?:.*)(?:e|x|episode|\n)(?:\s)(\d+)| # s 01 random123 e 02
                        (?:s|season)(?:\s)(\d+)(?:.*)(?:e|x|episode|\n)(\d+)| # s 01 random123 e02
                        (?:s|season)(\d+)(?:.*)(?:e|x|episode|\n)(?:\s)(\d+) # s01 random123 e 02
                        """, re.VERBOSE)

test="Hello seinfeld season 01episode 22 foo bar"

match = re.search(episode, test)
print match.group(1), match.group(2)

Следующий код выведет 01 22, как и ожидалось. Но что, если строка test будет выглядеть примерно так:

test="Hello seinfeld season 01 episode 22 foo bar"

Как я могу узнать, какую группу использовать? Это означает, что я не знаю, какое значение имеет test.

РЕДАКТИРОВАТЬ: Может быть, я мог бы проверить все группы на ценность и, если это правда, использовать эту конкретную группу. Но это похоже на неправильный способ сделать это.


person Markus Rexhepi-Lindberg    schedule 27.08.2015    source источник
comment
r\s*season\s*(\d+)\s*(?:e|x|эпизод)\s*(\d+) работает для предоставленных примеров тестовых строк и т. д. Пожалуйста, предоставьте набор тестовых строк для всех случаев, необходимых для расширения этого.   -  person    schedule 27.08.2015


Ответы (2)


Как насчет того, чтобы разбить каждый из шаблонов регулярных выражений на список, где каждый элемент содержит один шаблон регулярного выражения? Это поможет вам упорядочить шаблоны регулярных выражений, если вам нужно добавить/удалить больше шаблонов, разделив при этом каждый вариант. Вы также можете использовать именованные группы регулярных выражений.

Я изменил исходный пример двумя дополнительными изменениями: 1) отдельные шаблоны и 2) именованные группы как таковые:

import re

pattern1 = re.compile(r"""(?:s|season)(?:\s)(?P<s>\d+)(?:e|x|episode|\n)(?:\s)(?P<ep>\d+) # s 01e 02""", re.VERBOSE)
pattern2 = re.compile(r"""(?:s|season)(?P<s>\d+)(?:e|x|episode|\n)(?:\s)(?P<ep>\d+) # s01e 02""", re.VERBOSE)
pattern3 = re.compile(r"""(?:s|season)(?:\s)(?P<s>\d+)(?:e|x|episode|\n)(?P<ep>\d+) # s 01e02""", re.VERBOSE)
pattern4 = re.compile(r"""(?:s|season)(?P<s>\d+)(?:e|x|episode|\n)(?P<ep>\d+) # s01e02""", re.VERBOSE)
pattern5 = re.compile(r"""(?:s|season)(?P<s>\d+)(?:.*)(?:e|x|episode|\n)(?P<ep>\d+) # s01 random123 e02""", re.VERBOSE)
pattern6 = re.compile(r"""(?:s|season)(?:\s)(?P<s>\d+)(?:.*)(?:e|x|episode|\n)(?:\s)(?P<ep>\d+) # s 01 random123 e 02""", re.VERBOSE)
pattern7 = re.compile(r"""(?:s|season)(?:\s)(?P<s>\d+)(?:.*)(?:e|x|episode|\n)(?P<ep>\d+) # s 01 random123 e02""", re.VERBOSE)
pattern8 = re.compile(r"""(?:s|season)(?P<s>\d+)(?:.*)(?:e|x|episode|\n)(?:\s)(?P<ep>\d+) # s01 random123 e 02""", re.VERBOSE)

patterns = [pattern1, pattern2, pattern3, pattern4, pattern5, pattern6, pattern7, pattern8 ]

test="Hello seinfeld season 01episode 22 foo bar"

for idx, p in enumerate(patterns):
    m = re.search(p, test)
    if m:
        print('MATCHED PATTERN: {}'.format( patterns[idx].pattern ) )
        print('    SEASON:  {}'.format( m.group('s')) )
        print('    EPISODE: {}'.format( m.group('ep')) )

выход:

MATCHED PATTERN: (?:s|season)(?:\s)(?P<s>\d+)(?:e|x|episode|\n)(?:\s)(?P<ep>\d+) # s 01e 02
    SEASON:  01
    EPISODE: 22

MATCHED PATTERN: (?:s|season)(?:\s)(?P<s>\d+)(?:.*)(?:e|x|episode|\n)(?:\s)(?P<ep>\d+) # s 01 random123 e 02
    SEASON:  01
    EPISODE: 22

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

person cchi    schedule 27.08.2015
comment
Спасибо. Это кажется более плавным способом сделать это. Не знал, что можно называть группы. - person Markus Rexhepi-Lindberg; 27.08.2015
comment
Именованные группы действительно пригодятся, если у вас есть встроенные группы захвата. Кроме того, вы можете объединить все варианты шаблонов регулярных выражений в меньшее количество шаблонов с дополнительными параметрами, если количество шаблонов станет громоздким. - person cchi; 27.08.2015

Попробуйте это: \s*(season|s)\s*(\d+)(episode|e|x)\s*(\d+) ваши совпадающие слова в группе 2 и 4

import re
p = re.compile(ur'\s*(season|s)\s*(\d+)(episode|e|x)\s*(\d+)', re.MULTILINE)
test_str = u"Hello seinfeld season 01episode 22 foo bar\ns 01e 02\n"

re.findall(p, test_str)

Демо

person Ahosan Karim Asik    schedule 27.08.2015