Как сопоставить необязательную группу в конце строки с регулярным выражением? - PullRequest
2 голосов
/ 01 октября 2019

У меня есть строки, как показано ниже:

(1) Pay for zone 1234 for 1 hour
(2) Pay for zone 4567
(3) Pay for zone 1234 for 1 hour 30 minutes

и следующее регулярное выражение (https://regex101.com/r/MBWJUq/1):

(\d{4}).*(30 minutes|1 hour(?: 30 minutes)?|(?:[2-9]|1[0-9]|2[0-4]) hour(?: 30 minutes)?)

. Это хорошо работает со случаями (1) и (3), ноне работает с case (2). Как мне это исправить?

Работает с case (2), если я сделаю последнюю группу необязательной. Но тогда она не захватывает первую группу с case (1) и (3).

Ответы [ 2 ]

2 голосов
/ 01 октября 2019

Если вы хотите сохранить 2 группы захвата и хотите выбрать диапазон от 1-24 до hour и, возможно, пробел и 30 минут, вы можете сократить шаблон до:

(\d{4})(?:.* ((?:[1-9]|1[0-9]|2[0-4]) hour(?: 30 minutes)?))?

По частям

  • (\d{4}) Захват группа 1 Совпадение с 4 цифрами (Вы можете добавить границу слова \b)
  • (?: Без захватагруппа
    • .* Соответствует любому символу 0+ раз, за ​​которым следует пробел (или используйте .*\b)
    • ( Захват группа 2
      • (?:[1-9]|1[0-9]|2[0-4]) hour Соответствует диапазону 1-24, за которым следует час
      • (?: 30 minutes)? По выбору соответствует 30 минутам
    • ) Закрыть группу 2
  • )? Закрыть группу захвата и сделать ее необязательной

Regex demo

1 голос
/ 01 октября 2019

Я не сильно изменил pattern, потому что вы не объяснили, что именно хотите извлечь.

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

, теперь вторая группа также должна быть вставлена ​​в non capturing group, чтобы совпадение либо текста заканчивалось чем-то вроде for 1 hour иликонец строки \n.

проверьте это:

import re

text = """
(1) Pay for zone 1234 for 1 hour
(2) Pay for zone 4567
(3) Pay for zone 1234 for 1 hour 30 minutes
"""

RE = r'(\d{4}).*?(?:(30 minutes|1 hour(?: 30 minutes)?|(?:[2-9]|1[0-9]|2[0-4]) hour(?: 30 minutes)?)|\n)'
# same thing using compile with flags MULTILINE
# RE = re.compile(r'(\d{4}).*?(?:(30 minutes|1 hour(?: 30 minutes)?|(?:[2-9]|1[0-9]|2[0-4]) hour(?: 30 minutes)?)|$)', flags=re.MULTILINE)

print(re.findall(RE, text))

ВЫХОД:

  [('1234', '1 hour'), ('4567', ''), ('1234', '1 hour 30 minutes')]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...