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多线程抓取天涯帖子内容示例
Apr 03 Python
Python ORM框架SQLAlchemy学习笔记之数据添加和事务回滚介绍
Jun 10 Python
Python中IPYTHON入门实例
May 11 Python
python魔法方法-自定义序列详解
Jul 21 Python
Python在不同目录下导入模块的实现方法
Oct 27 Python
Python 实现12306登录功能实例代码
Feb 09 Python
python numpy 一维数组转变为多维数组的实例
Jul 02 Python
python调用百度语音REST API
Aug 30 Python
Python lambda表达式用法实例分析
Dec 25 Python
python 判断矩阵中每行非零个数的方法
Jan 26 Python
如何基于Python创建目录文件夹
Dec 31 Python
Python pymsql模块的使用
Sep 07 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
wamp下修改mysql访问密码的解决方法
2013/05/07 PHP
ThinkPHP的MVC开发机制实例解析
2014/08/23 PHP
PHP操作Postgresql封装类与应用完整实例
2018/04/24 PHP
input按钮的事件处理大全
2010/12/10 Javascript
extjs ColumnChart设置不同的颜色实现代码
2013/05/17 Javascript
jQuery避免$符和其他JS库冲突的方法对比
2014/02/20 Javascript
仿百度联盟对联广告实现代码
2014/08/30 Javascript
jQuery实现垂直半透明手风琴特效代码分享
2015/08/21 Javascript
javascript实现的上下无缝滚动效果
2016/09/19 Javascript
浅谈AngularJs指令之scope属性详解
2016/10/24 Javascript
bootstrap网格系统使用方法解析
2017/01/13 Javascript
jQuery实现复选框的全选和反选
2017/02/02 Javascript
Vue.js 2.0 移动端拍照压缩图片预览及上传实例
2017/04/27 Javascript
详解Angular 自定义结构指令
2017/06/21 Javascript
jQuery实现腾讯信用界面(自制刻度尺)样式
2017/08/15 jQuery
React-Native之定时器Timer的实现代码
2017/10/04 Javascript
react实现菜单权限控制的方法
2017/12/11 Javascript
详解angular应用容器化部署
2018/08/14 Javascript
IE浏览器下JS脚本提交表单后,不能自动提示问题解决方法
2019/06/04 Javascript
详解Nuxt内导航栏的两种实现方式
2020/04/16 Javascript
详解Vue的mixin策略
2020/11/19 Vue.js
Python单元测试框架unittest简明使用实例
2015/04/13 Python
Python类属性与实例属性用法分析
2015/05/09 Python
numpy中索引和切片详解
2017/12/15 Python
TensorFlow:将ckpt文件固化成pb文件教程
2020/02/11 Python
python中封包建立过程实例
2021/02/18 Python
HTML5中5个简单实用的API(第二篇,含全屏、可见性、拍照、预加载、电池状态)
2014/05/07 HTML / CSS
英国女装网上商店:I Saw It First
2018/10/18 全球购物
毕业实习个人鉴定范文
2013/12/10 职场文书
暑期社会实践先进个人主要事迹
2014/05/22 职场文书
收款委托书范本
2014/09/11 职场文书
居委会工作总结2015
2015/05/18 职场文书
公诉意见书范文
2015/06/05 职场文书
2016年第16个全民国防教育日宣传活动总结
2016/04/05 职场文书
Python包管理工具pip的15 个使用小技巧
2021/05/17 Python
Golang标准库syscall详解(什么是系统调用)
2021/05/25 Golang