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 基础学习第二弹 类属性和实例属性
Aug 27 Python
python对配置文件.ini进行增删改查操作的方法示例
Jul 28 Python
Python中一行和多行import模块问题
Apr 01 Python
浅谈Pandas中map, applymap and apply的区别
Apr 10 Python
Python实现的逻辑回归算法示例【附测试csv文件下载】
Dec 28 Python
python实现维吉尼亚算法
Mar 20 Python
Python自动抢红包教程详解
Jun 11 Python
关于Python形参打包与解包小技巧分享
Aug 24 Python
wxPython窗体拆分布局基础组件
Nov 19 Python
pandas DataFrame 数据选取,修改,切片的实现
Apr 24 Python
python属于哪种语言
Aug 16 Python
Python 图片添加美颜效果
Apr 28 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全角字符转换为半角函数
2014/02/07 PHP
JS异常处理try..catch语句的作用和实例
2014/05/05 PHP
PHP判断用户是否已经登录(跳转到不同页面或者执行不同动作)
2016/09/22 PHP
Laravel使用scout集成elasticsearch做全文搜索的实现方法
2018/11/30 PHP
微博@符号的用户名提示效果。(想@到谁?)
2010/11/05 Javascript
用Javascript实现Windows任务管理器的代码
2012/03/27 Javascript
jquery的live使用注意事项
2014/02/18 Javascript
javaScript使用EL表达式的几种方式
2014/05/27 Javascript
node.js+jQuery实现用户登录注册AJAX交互
2017/04/28 jQuery
浅谈Vue 初始化性能优化
2017/08/31 Javascript
JS实现百度搜索接口及链接功能实例代码
2018/02/02 Javascript
JS简单实现查看文档创建日期、修改日期和文档大小的方法示例
2018/04/08 Javascript
纯js封装的ajax功能函数与用法示例
2018/05/14 Javascript
全面解析vue router 基本使用(动态路由,嵌套路由)
2018/09/02 Javascript
layui-table表复选框勾选的所有行数据获取的例子
2019/09/13 Javascript
使用JavaScript和MQTT开发物联网应用示例解析
2020/08/07 Javascript
Python元字符的用法实例解析
2018/01/17 Python
Python 网络爬虫--关于简单的模拟登录实例讲解
2018/06/01 Python
Python中矩阵创建和矩阵运算方法
2018/08/04 Python
Python获取好友地区分布及好友性别分布情况代码详解
2019/07/10 Python
微信小程序python用户认证的实现
2019/07/29 Python
python GUI库图形界面开发之PyQt5下拉列表框控件QComboBox详细使用方法与实例
2020/02/27 Python
卸载tensorflow-cpu重装tensorflow-gpu操作
2020/06/23 Python
日本快乐生活方式购物网站:Shop Japan
2018/07/17 全球购物
怎样让char类型的东西转换成int类型
2013/12/09 面试题
简短证婚人证婚词
2014/01/09 职场文书
写给女朋友的检讨书
2014/01/28 职场文书
促销活动方案模板
2014/02/24 职场文书
综合素质评价思想道德自我评价
2015/03/09 职场文书
2015年学校教科室工作总结
2015/07/20 职场文书
大学生党课感想
2015/08/11 职场文书
优秀团员主要事迹材料
2015/11/05 职场文书
2017年寒假少先队活动总结
2016/04/06 职场文书
python学习之panda数据分析核心支持库
2021/05/07 Python
Python趣味挑战之教你用pygame画进度条
2021/05/31 Python
详解Redis复制原理
2021/06/04 Redis