Регулярное выражение для соответствия возрасту, написанному в текстовом формате

Я пытаюсь извлечь возраст человека из предложения; это немного упрощено, но это все для исследовательского проекта. Я знаю, что в предложении возрасту всегда предшествует либо двоеточие, за которым следует 0 или более пробелов, либо двоеточие, пробелы, несколько слов и некоторые пробелы (пример: «персонаж: прекрасная восьмидесятилетняя бабушка», I хотите регулярное выражение, которое позволит мне извлечь «восемьдесят» из одной из групп). Я использую библиотеку python re, и мой код зависает в этом примере (код и пример ниже):

regex_age_string = r'([:]*[ ]*)?((([a-z]*)([ -]*))+)([ -]+)(year)'
regex_age_string = re.compile(regex_age_string, re.DOTALL)
sentence = 'history:   four year-old boy was really sad when he found 
out the toy was broken'
age_extract_string = re.search(regex_age_string, sentence)
print(age_extract_string.group())
print(age_extract_string.group(2))

Однако работает, когда я сокращаю предложение, вырезая несколько хвостовых слов. Я читал о зависании поиска регулярных выражений из-за катастрофического отката, но я не уверен, как это применимо здесь / как это исправить.

year всегда следует за вашим возрастом?

Allan 02.05.2018 09:55

Причина обычная: катастрофический откат. Может быть, все, что вам нужно, это извлечь любой текст между : и year? Попробуйте :\s*(.*?)\s*year. Или, если вы хотите ограничить захват только буквами, - и пробелами, :\s*([a-z\s-]*?)\s*year.

Wiktor Stribiżew 02.05.2018 09:56

можешь привести еще примеры? возраст может быть несколько слов? (например, двадцать один)

Susensio 02.05.2018 10:01

Возраст может состоять из нескольких слов, поэтому я хотел бы, чтобы это отражало возраст в тех случаях, когда мне «двадцать один», или «двадцать один год», или «двадцать один год».

Maria 02.05.2018 10:03

Так что вроде работает 'r':\s*([a-z\s-]*?)\s*[-]*year'. Может кто-нибудь объяснить, что было в моем случае катастрофическим откатом? Я понимаю концепцию на высоком уровне, но понимание того, что именно в моем примере было проблематичным, было бы очень полезно для изучения!

Maria 02.05.2018 10:06

вам нужно сузить граничные условия. представьте себе два предложения: «история: четыре года» и «история: двадцать четыре года». Регулярному выражению кажется трудным отличить «есть» от «двадцать» без дополнительной логики. Какое число? У них одинаковый контекст. Лично я бы написал некоторую логику для этих крайних случаев, что-то вроде check if word is in (set of multiples of ten), и применил бы ее к слову перед «четыре» в этом примере.

Susensio 02.05.2018 10:14

Привет Мария, см. мой ответ ниже. Дело в том, что у вас есть последовательность необязательных подшаблонов в количественно определенной по + группе внутри паттерна. Это почти всегда приводит к зависанию.

Wiktor Stribiżew 02.05.2018 11:06

Совет новичкам: если ответ решает вашу проблему, примите его, щелкнув большую галочку (✓) рядом с ним, и, при желании, проголосуйте за него (для голосования требуется не менее 15 очков репутации). Если вы нашли другие ответы полезными, проголосуйте за них. Принятие и голосование помогают будущим читателям. См. [Соответствующую статью Справочного центра] [1] [1]: stackoverflow.com/help/someone-answers

Allan 11.05.2018 08:01
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
8
317
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Причина, по которой ваше регулярное выражение вызывает замедление, - катастрофический откат. Это вызвано последовательностью необязательных паттернов внутри определенной количественной группы - (([a-z]*)([ -]*))+.

Фактически вы можете сопоставить любые буквы, пробелы или дефисы от : до year:

r':\s*([a-z\s-]*?)\s*-*year'

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

Подробности

  • : - :
  • \s* - 0+ белых мазков
  • ([a-z\s-]*?) - Группа 1: 0+ строчных букв ASCII, пробелов или дефисов
  • \s* - 0+ пробелов
  • -* - 0+ - символов
  • year - подстрока.

Сработало отлично! Спасибо! И спасибо за быстрый ответ невероятно.

Maria 14.05.2018 09:16

@ Мария Рада, что это произошло. Если вы еще не проголосовали за ответ, сделайте это (см. Как проголосовать за Stack Overflow?).

Wiktor Stribiżew 14.05.2018 09:30

Основываясь на вашем описании, вы можете использовать следующее регулярное выражение для получения возраста (без учета регистра для людей в возрасте от 0-999 лет)

(?i)\b(?:zero|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)\b(?=\s*year)|\b(?:(?:one|two|three|four|five|six|seven|eight|nine)? hundred(?:\sand)?\s)?(?:(?:twenty|thirty|forty|fifty|sixty|seventy|eighty|ninety)[\s-]?)?\b(?:one|two|three|four|five|six|seven|eight|nine)?(?=\syear)

Это сработало следующие предложения:

history:   Zero year-old baby
history:   FOUR year-old boy was really sad when he found 
out the toy was broken
character: a lovely eighty-three year old grandma
test: a nice eighty year-old father
character: a lovely eighty years old grandma
character: a lovely ninety-nine year old grandma
research: a great eight year-old brother
character: a lovely one hundred ninety-nine year old increadible grandma
character: a lovely one hundred and ninety-nine year old really increadible grandma
character: a lovely one hundred one year old super increadible grandma
character: a lovely nine hundred and ninety-nine year old super super increadible grandma
character: a lovely nine hundred ninety nine year old super super increadible grandma

Не стесняйтесь адаптировать его, чтобы перейти к тысячи и миллионы летней бабушке

ДЕМО на regex101.com

Другие вопросы по теме