首页 > 解决方案 > 匹配可选模式的第一次出现

问题描述

我正在尝试在混乱的字符串中提取名称,如下所示:

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

Where[…]可以是没有规则模式的任何字符的连续。

所需的输出是:

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-]+)?.*

这是一个演示

我正在使用惰性量词*?来查找字符串中某种锚点(例如subspxvar)的第一次出现,我可以使用这些锚点来匹配给定的模式。问题是我无法让正则表达式适用于所有实例,因为(\sx\s+[a-z-]+)?并且(\svar[\.\s]+[a-z-]+)?是可选的,因为匹配的模式并不存在于所有字符串中。

是否有解决此问题的简单解决方案?

标签: regexpcre

解决方案


您可以使用可选的非捕获组包装可选模式,以使必要的捕获组成为强制性的,并强制正则表达式引擎至少尝试一次搜索模式。

这意味着您需要将所有.*?(pattern-to-extract)?模式更改为(?:.*?(pattern-to-extract))?. 当整个组是可选的时,它可能会匹配一个空字符串并认为工作已完成。当该组被一个可选组包裹时,它至少会尝试一次,并且.*?保证初始值会根据需要扩展多次以达到捕获组模式。

利用

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

请注意,字符类中的点与文字点匹配,无需转义它们。

请参阅正则表达式演示


推荐阅读