Я пытаюсь извлечь возраст человека из предложения; это немного упрощено, но это все для исследовательского проекта. Я знаю, что в предложении возрасту всегда предшествует либо двоеточие, за которым следует 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
? Попробуйте :\s*(.*?)\s*year
. Или, если вы хотите ограничить захват только буквами, -
и пробелами, :\s*([a-z\s-]*?)\s*year
.
можешь привести еще примеры? возраст может быть несколько слов? (например, двадцать один)
Возраст может состоять из нескольких слов, поэтому я хотел бы, чтобы это отражало возраст в тех случаях, когда мне «двадцать один», или «двадцать один год», или «двадцать один год».
Так что вроде работает 'r':\s*([a-z\s-]*?)\s*[-]*year'
. Может кто-нибудь объяснить, что было в моем случае катастрофическим откатом? Я понимаю концепцию на высоком уровне, но понимание того, что именно в моем примере было проблематичным, было бы очень полезно для изучения!
вам нужно сузить граничные условия. представьте себе два предложения: «история: четыре года» и «история: двадцать четыре года». Регулярному выражению кажется трудным отличить «есть» от «двадцать» без дополнительной логики. Какое число? У них одинаковый контекст. Лично я бы написал некоторую логику для этих крайних случаев, что-то вроде check if word is in (set of multiples of ten)
, и применил бы ее к слову перед «четыре» в этом примере.
Привет Мария, см. мой ответ ниже. Дело в том, что у вас есть последовательность необязательных подшаблонов в количественно определенной по +
группе внутри паттерна. Это почти всегда приводит к зависанию.
Совет новичкам: если ответ решает вашу проблему, примите его, щелкнув большую галочку (✓) рядом с ним, и, при желании, проголосуйте за него (для голосования требуется не менее 15 очков репутации). Если вы нашли другие ответы полезными, проголосуйте за них. Принятие и голосование помогают будущим читателям. См. [Соответствующую статью Справочного центра] [1] [1]: stackoverflow.com/help/someone-answers
Причина, по которой ваше регулярное выражение вызывает замедление, - катастрофический откат. Это вызвано последовательностью необязательных паттернов внутри определенной количественной группы - (([a-z]*)([ -]*))+
.
Фактически вы можете сопоставить любые буквы, пробелы или дефисы от :
до year
:
r':\s*([a-z\s-]*?)\s*-*year'
Смотрите демонстрация регулярного выражения.
Подробности
:
- :
\s*
- 0+ белых мазков([a-z\s-]*?)
- Группа 1: 0+ строчных букв ASCII, пробелов или дефисов\s*
- 0+ пробелов-*
- 0+ -
символовyear
- подстрока.Сработало отлично! Спасибо! И спасибо за быстрый ответ невероятно.
@ Мария Рада, что это произошло. Если вы еще не проголосовали за ответ, сделайте это (см. Как проголосовать за Stack Overflow?).
Основываясь на вашем описании, вы можете использовать следующее регулярное выражение для получения возраста (без учета регистра для людей в возрасте от 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
Не стесняйтесь адаптировать его, чтобы перейти к тысячи и миллионы летней бабушке
year
всегда следует за вашим возрастом?