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中的exec、eval使用实例
Sep 23 Python
python更新列表的方法
Jul 28 Python
Python中操作符重载用法分析
Apr 29 Python
使用Python &amp; Flask 实现RESTful Web API的实例
Sep 19 Python
Python将多份excel表格整理成一份表格
Jan 03 Python
python遍历文件夹下所有excel文件
Jan 03 Python
Python多进程fork()函数详解
Feb 22 Python
python学习开发mock接口
Apr 28 Python
python从list列表中选出一个数和其对应的坐标方法
Jul 20 Python
Python嵌入C/C++进行开发详解
Jun 09 Python
python爬虫scrapy框架之增量式爬虫的示例代码
Feb 26 Python
python自动化调用百度api解决验证码
Apr 13 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
基于PHP生成静态页的实现方法
2013/05/10 PHP
php清除和销毁session的方法分析
2015/03/19 PHP
thinkPHP js文件中U方法不被解析问题的解决方法
2016/12/05 PHP
PHP实现将标点符号正则替换为空格的方法
2017/08/09 PHP
PHP简单验证码功能机制实例详解
2019/03/27 PHP
JavaScript 事件记录使用说明
2009/10/20 Javascript
强大的jquery插件jqeuryUI做网页对话框效果!简单
2011/04/14 Javascript
让innerText在firefox火狐和IE浏览器都能用的写法
2011/05/14 Javascript
JavaScript检查某个function是否是原生代码的方法
2014/08/20 Javascript
JQuery实现超链接鼠标提示效果的方法
2015/06/10 Javascript
JS实现点击复选框将按钮或文本框变为灰色不可用的方法
2015/08/11 Javascript
Angularjs2不同组件间的通信实例代码
2017/05/06 Javascript
原生js轮播特效
2017/05/18 Javascript
jQuery实现的页面详情展开收起功能示例
2018/06/11 jQuery
[32:39]完美世界DOTA2联赛循环赛 Forest vs Inki BO2第一场 11.04
2020/11/04 DOTA
python在linux系统下获取系统内存使用情况的方法
2015/05/11 Python
Python根据区号生成手机号码的方法
2015/07/08 Python
python安装mysql-python简明笔记(ubuntu环境)
2016/06/25 Python
python访问抓取网页常用命令总结
2017/04/11 Python
简单实现python收发邮件功能
2018/01/05 Python
Python三种遍历文件目录的方法实例代码
2018/01/19 Python
python导出hive数据表的schema实例代码
2018/01/22 Python
对python周期性定时器的示例详解
2019/02/19 Python
python设计tcp数据包协议类的例子
2019/07/23 Python
tensorflow 获取checkpoint中的变量列表实例
2020/02/11 Python
Django实现后台上传并显示图片功能
2020/05/29 Python
Python实现数字的格式化输出
2020/08/01 Python
python判断字符串以什么结尾的实例方法
2020/09/18 Python
CSS3模拟动画下拉菜单效果
2017/04/12 HTML / CSS
Ootori在线按摩椅店:一家专业的按摩椅制造商
2019/04/10 全球购物
党支部三会一课计划
2014/09/24 职场文书
2014年药剂科工作总结
2014/11/26 职场文书
生产车间主任岗位职责
2015/04/08 职场文书
会计专业自荐信范文
2019/05/22 职场文书
MySQL创建高性能索引的全步骤
2021/05/02 MySQL
Oracle 11g数据库使用expdp每周进行数据备份并上传到备份服务器
2022/06/28 Oracle