Python正则表达式教程之三:贪婪/非贪婪特性
本文深入解析Python正则表达式中的贪婪与非贪婪匹配机制。通过具体代码示例,详细阐述默认贪婪行为导致的匹配偏差,并介绍使用问号?实现非贪婪匹配的方法。此外,还探讨了利用零宽断语(?=)和(?!解决字符消耗问题的技巧,帮助开发者更精准地控制正则表达式的匹配行为。
贪婪与非贪婪匹配概述
在前面的章节中,我们已经简要介绍了Python正则表达式的基础知识以及捕获组的概念。在本文中,我们将重点总结正则表达式中至关重要的贪婪与非贪婪特性。
贪婪匹配机制
贪婪匹配
默认情况下,正则表达式引擎会执行贪婪匹配。所谓“贪婪”,是指当存在多种可能的匹配长度时,引擎会优先选择最长的那一个。例如,下面这个正则表达式的初衷是提取人物对话内容,但由于贪婪特性的影响,导致了匹配结果不符合预期:
>>> sentence = """You said "why?" and I say "I don't know"."""
>>> re.findall(r'"(.*)"', sentence)
['why?" and I say "I don\'t know']
再看以下几个例子,它们同样展示了正则表达式“贪婪”匹配的行为特征:
>>> re.findall('hi*', 'hiiiii')
['hiiiii']
>>> re.findall('hi{2,}', 'hiiiii')
['hiiiii']
>>> re.findall('hi{1,3}', 'hiiiii')
['hiii']
非贪婪匹配实现
非贪婪匹配
如果我们希望正则表达式以“非贪婪”的方式进行匹配,必须通过特定的语法明确指定:
{2,5}? 捕获2-5次,但是优先次数少的匹配
这里的问号?可能会让人产生困惑,因为它之前已经被定义为表示前面的字符出现0次或1次。只需记住一点:当问号出现在表示不定次数量的正则表达式部分之后时,它即表示非贪婪匹配。
沿用上面的几个例子,若采用非贪婪匹配,结果如下所示:
>>> re.findall('hi*?', 'hiiiii')
['h']
>>> re.findall('hi{2,}?', 'hiiiii')
['hii']
>>> re.findall('hi{1,3}?', 'hiiiii')
['hi']
在另一个示例中,使用非贪婪匹配后的结果如下:
>>> sentence = """You said "why?" and I say "I don't know"."""
>>> re.findall(r'"(.*?)"', sentence)
['why?', "I don't know"]
捕获与字符消耗问题
捕获与非贪婪的关联
严格来说,这一部分并不属于非贪婪特性的范畴。但由于其行为模式与非贪婪匹配相似,为了方便记忆和理解,我们将相关内容放在一起进行讲解。
(?=abc) 捕获,但不消耗字符,且匹配abc
(?!abc) 捕获,不消耗,且不匹配abc
在正则表达式的匹配过程中,实际上存在“消耗字符”的概念。也就是说,一旦某个字符在匹配过程中被检索(即被消耗)过,后续的匹配操作将不再检索该字符。
了解这一特性有何实际用途?我们通过例子来说明。例如,我们的目标是找出字符串中出现次数超过1次的单词:
>>> sentence = "Oh what a day, what a lovely day!"
>>> re.findall(r'\b(\w+)\b.*\b\1\b', sentence)
['what']
显然,这样的正则表达式无法完成任务。原因在于,当第一个(\w+)匹配到“what”,且其后的\1也匹配到第二个“what”时,“Oh what a day, what”这一段子串已经被正则表达式完全消耗。因此,后续的匹配将从第二个“what”之后开始,导致只能找出一个出现了两次的单词。
解决方案便与前面提到的(?=abc)语法相关。这种语法可以在进行分组匹配的同时,不消耗字符串!因此,正确的写法应该是:
>>> re.findall(r'\b(\w+)\b(?=.*\b\1\b)', sentence)
['what', 'a', 'day']
如果我们需要匹配一个至少包含两个不同字母的单词,则可以使用(?!abc)的语法:
>>> re.search(r'([a-z]).*(?!\1)[a-z]', 'aa', re.IGNORECASE)
>>> re.search(r'([a-z]).*(?!\1)[a-z]', 'ab', re.IGNORECASE)
<_sre.SRE_Match object; span=(0, 2), match='ab'>
总结
总结
以上就是Python正则表达式中关于贪婪特性的全部内容。希望本文的内容能对大家学习或使用Python有所帮助。如有任何疑问,欢迎留言交流。在下一篇文章中,我将继续总结Python正则表达式re模块中一些API的具体用法,请继续关注本站。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













