Сопоставить первое вхождение необязательного шаблона - PullRequest
2 голосов
/ 25 мая 2019

Я пытаюсь извлечь имена в грязных строках, как показано ниже:

genus species subsp. name […] x name […] var. name; genus2 species2 subsp. name2 var. name2  
genus species subsp. name […] x name […] var. name  
genus species subsp. name […] var name  
genus species subsp. name var. name  
genus species subsp. name

Где […] может быть последовательностью любых символов без регулярных шаблонов.

Желаемый результат:

subsp. name x name var. name  
subsp. name x name var. name  
subsp. name var. name  
subsp. name var. name  
subsp. name

Мое регулярное выражение выглядит так:

(?i).*?\b((?:aff|cf|ssp|subsp|var)[\.\s]+)([a-z-]+).*?(\sx\s+[a-z-]+)?.*?(\svar[\.\s]+[a-z-]+)?.*

Вот демоверсия .

Я использую ленивый квантификатор *?, чтобы найти первое вхождение каких-либо якорей (например, subsp, x и var) в строках, которые я могу использовать для соответствия заданному шаблону. Проблема в том, что мне не удается настроить регулярное выражение для всех экземпляров, поскольку (\sx\s+[a-z-]+)? и (\svar[\.\s]+[a-z-]+)? являются необязательными, поскольку сопоставленные шаблоны не существуют во всех строках.

Есть ли простое решение, чтобы обойти эту проблему?

1 Ответ

0 голосов
/ 25 мая 2019

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

Это означает, что вам нужно изменить все .*?(pattern-to-extract)? шаблоны на (?:.*?(pattern-to-extract))?.Когда вся группа является необязательной, она может соответствовать пустой строке и считать работу выполненной.Когда группа обернута необязательной группой, она пробуется хотя бы один раз, и начальный .*? гарантированно будет расширен столько раз, сколько необходимо для получения шаблона группы захвата.

Использование

(?i).*?\b((?:aff|cf|ssp|subsp|var)[.\s]+)([a-z-]+)(?:.*?(\sx\s+[a-z-]+))?(?:.*?(\svar[.\s]+[a-z-]+))?.*

Обратите внимание, что точки внутри классов символов соответствуют буквальным точкам, не нужно их экранировать.

См. Демонстрационную версию regex .

...