Понимание группы и или в регулярном выражении

#python #regex #re

Вопрос:

Я ищу такие слова, как «один год», «два года», «2-3 года» или «3-4 года» в длинной строке. Я пытался сделать это с помощью регулярных выражений. Но я не уверен, что понял это, когда участвуют группы.

Давайте посмотрим, что я имею в виду:

 import re

text = 'one year, honey 2-5 year, dressed six, ten'
pattern = r'(one|two|three|four|five|six|seven|eight|nine|ten| 
                  eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen| 
                  eighteen|nineteen|twenty|[0-9] [- ]*[0-9]*)[  ]*year?'

re.findall(pattern, text)  # ['one', '2-5']

 

Моя проблема в том, что я хочу ['one year', '2-5 years'] . Я не знаю, как это сделать. Если бы я забыл о цифрах в словах:

 pattern = r'[0-9] [- ]*[0-9]*[  ]*year?'
re.findall(pattern, text)  # ['2-5 years']
 

Почему я попал years во второй, а не в первый? Как я могу изменить его, чтобы получить годы в первом?

Заранее спасибо,

Комментарии:

1. [0-9] [- ]*[0-9]* должен быть первым элементом в списке чередования

2. Почему после буквы » р » стоит вопросительный знак? Разве ты не имеешь в виду years? вместо этого?

Ответ №1:

Сначала вам нужно исправить шаблон, чтобы он соответствовал числам. Вот пример:

 >>> pattern = r'''(?x)b(?:[0-9] (?:[- ]*[0-9] )?|one|two|three|four|five|six|seven|eight|nine|ten
|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)
[  ]*years?b'''
>>> re.findall(pattern, text)
['one year', '2-5 year']
 

Смотрите демонстрационную версию Python и демонстрационную версию регулярных выражений.

Подробные сведения

  • (?x) re.X / re.VERBOSE встроенный модификатор
  • b — граница слов
  • (?: — начало группы без захвата
    • [0-9] (?:[- ]*[0-9] )? — одна или несколько цифр, за которыми следуют ноль или несколько пробелов, или - , а затем одна или несколько цифр
    • |one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty — одно из слов в списке чередования
  • ) — конец группы без захвата
  • [ ]* — ноль или больше или пробелы
  • years? year или years
  • b — граница слов.

Комментарии:

1. @Xbel Также соответствует «Я купил телефон много лет назад».

Ответ №2:

В вашем регулярном выражении year? должно быть years? потому, что это конечная буква «s», которая является необязательной, а не «r». Вам также необходимо использовать так называемые группы без захвата (?: ... ) , чтобы получить строку, соответствующую всему регулярному выражению; в противном случае вы получите только строки, соответствующие заключенным в скобки подвыражениям.

Для улучшения читаемости также рекомендуется разделить длинное регулярное выражение на подвыражения и дать им значимые имена. Попробуйте это:

 import re

text = 'one year, honey 2-5 year, dressed six, ten'
numberWordsRe = r'one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty'
numberOrIntervalRe=r'd (?:s*-s*d )'
pattern = r'b(?:'   numberWordsRe   r'|'   numberOrIntervalRe   r')s years?b'

print re.findall(pattern, text)
 

Комментарии:

1. Это уточняющие комментарии. Танков много.