Python正则表达式教程之三:贪婪/非贪婪特性


Posted in Python onMarch 02, 2017

之前已经简单介绍了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的用法,请继续关注三水点靠木。

Python 相关文章推荐
Python生成器(Generator)详解
Apr 13 Python
Django中的ajax请求
Oct 19 Python
Python利用递归实现文件的复制方法
Oct 27 Python
python爬虫 execjs安装配置及使用
Jul 30 Python
python Qt5实现窗体跟踪鼠标移动
Dec 13 Python
python 字典套字典或列表的示例
Dec 16 Python
Python嵌套函数,作用域与偏函数用法实例分析
Dec 26 Python
Python如何基于smtplib发不同格式的邮件
Dec 30 Python
python GUI库图形界面开发之PyQt5不规则窗口实现与显示GIF动画的详细方法与实例
Mar 09 Python
Django模板获取field的verbose_name实例
May 19 Python
使用Python pip怎么升级pip
Aug 11 Python
python将字典内容写入json文件的实例代码
Aug 12 Python
Python正则表达式教程之二:捕获篇
Mar 02 #Python
Python正则表达式教程之一:基础篇
Mar 02 #Python
Python单例模式实例详解
Mar 01 #Python
python实现字典(dict)和字符串(string)的相互转换方法
Mar 01 #Python
python 截取 取出一部分的字符串方法
Mar 01 #Python
详解Python中的静态方法与类成员方法
Feb 28 #Python
python基于itchat实现微信群消息同步机器人
Feb 27 #Python
You might like
Zerg兵种介绍
2020/03/14 星际争霸
经典的星际争霸,满是回忆的BGM
2020/04/09 星际争霸
风味层面去分析咖啡油脂
2021/03/03 咖啡文化
PHP新手上路(五)
2006/10/09 PHP
Codeigniter校验ip地址的方法
2015/03/21 PHP
PHP中session跨子域的三种实现方法
2016/07/25 PHP
脚本吧 - 幻宇工作室用到js,超强推荐expand.js
2006/12/23 Javascript
List the UTC Time on a Computer
2007/06/11 Javascript
ExtJs 3.1 XmlTreeLoader Example Error
2010/02/09 Javascript
jQueryUI写一个调整分类的拖放效果实现代码
2012/05/10 Javascript
关于IE中getElementsByClassName不能用的问题解决方法
2013/08/26 Javascript
javascritp添加url参数将参数加入到url中
2014/09/25 Javascript
JS中字符串trim()使用示例
2015/05/26 Javascript
jQuery中inArray方法注意事项分析
2016/01/25 Javascript
Angularjs在初始化未完毕时出现闪烁问题的解决方法分析
2016/08/05 Javascript
js实现精确到毫秒的倒计时效果
2016/08/05 Javascript
js改变透明度实现轮播图的算法
2020/08/24 Javascript
AngularJS全局警告框实现方法示例
2017/05/18 Javascript
nuxt框架中路由鉴权之Koa和Session的用法
2018/05/09 Javascript
微信小程序轮播图swiper代码详解
2020/12/01 Javascript
js重写alert事件(避免alert弹框标题出现网址)
2020/12/04 Javascript
Djang中静态文件配置方法
2015/07/30 Python
Python实现比较扑克牌大小程序代码示例
2017/12/06 Python
python使用folium库绘制地图点击框
2018/09/21 Python
python实现生成Word、docx文件的方法分析
2019/08/30 Python
如何使用Python多线程测试并发漏洞
2019/12/18 Python
利用keras使用神经网络预测销量操作
2020/07/07 Python
Camille Jewelry官网:现代女性时尚首饰
2019/07/07 全球购物
毕业生护理专业个人求职信范文
2014/01/04 职场文书
大学生村官心得体会范文
2014/01/04 职场文书
副厂长岗位职责
2014/02/02 职场文书
求职教师自荐书
2014/06/19 职场文书
小学生感恩老师演讲稿
2014/08/28 职场文书
golang 定时任务方面time.Sleep和time.Tick的优劣对比分析
2021/05/05 Golang
Django migrate报错的解决方案
2021/05/20 Python
SpringBoot实现异步事件驱动的方法
2021/06/28 Java/Android