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使用win32com在百度空间插入html元素示例
Feb 20 Python
详解Python发送邮件实例
Jan 10 Python
Python 专题五 列表基础知识(二维list排序、获取下标和处理txt文本实例)
Mar 20 Python
python web.py开发httpserver解决跨域问题实例解析
Feb 12 Python
python requests 测试代理ip是否生效
Jul 25 Python
python 循环读取txt文档 并转换成csv的方法
Oct 26 Python
django使用LDAP验证的方法示例
Dec 10 Python
python 切换root 执行命令的方法
Jan 19 Python
解决python打不开文件(文件不存在)的问题
Feb 18 Python
使用python的pyplot绘制函数实例
Feb 13 Python
Python还能这么玩之只用30行代码从excel提取个人值班表
Jun 05 Python
Python实现照片卡通化
Dec 06 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
深入理解:单一入口、MVC、ORM、CURD、ActiveRecord概念
2013/06/06 PHP
基于PHP输出缓存(output_buffering)的深入理解
2013/06/13 PHP
php中关于长度计算容易混淆的问题分析
2016/05/27 PHP
浅谈PHP中pack、unpack的详细用法
2018/03/12 PHP
PHP中SESSION过期设置
2021/03/09 PHP
jQuery判断checkbox选中状态
2016/05/12 Javascript
Javascript基础学习笔记(菜鸟必看篇)
2016/07/22 Javascript
原生JS:Date对象全面解析
2016/09/06 Javascript
vue.js表格分页示例
2016/10/18 Javascript
jQuery 的 ready()的纯js替代方法
2016/11/20 Javascript
RequireJS 依赖关系的实例(推荐)
2017/01/21 Javascript
js实现复制功能(多种方法集合)
2018/01/06 Javascript
vue-router 组件复用问题详解
2018/01/22 Javascript
jquery实现下载图片功能
2019/07/18 jQuery
vue props default Array或是Object的正确写法说明
2020/07/30 Javascript
[00:33]DOTA2上海特级锦标赛 CDEC战队宣传片
2016/03/04 DOTA
Python Web框架Flask中使用新浪SAE云存储实例
2015/02/08 Python
Python实现对比不同字体中的同一字符的显示效果
2015/04/23 Python
python实现淘宝秒杀聚划算抢购自动提醒源码
2020/06/23 Python
Django框架模板介绍
2019/01/15 Python
Python基本socket通信控制操作示例
2019/01/30 Python
详解Django+uwsgi+Nginx上线最佳实战
2019/03/14 Python
基于FME使用Python过程图解
2020/05/13 Python
纯css3制作的火影忍者写轮眼开眼至轮回眼及进化过程实例
2014/11/11 HTML / CSS
Html5之title吸顶功能
2018/06/04 HTML / CSS
SmartBuyGlasses荷兰:购买太阳镜和眼镜
2020/03/16 全球购物
宿舍违规检讨书
2014/01/12 职场文书
总经理司机岗位职责
2014/02/06 职场文书
实习协议书范本
2014/04/22 职场文书
公司2014年度工作总结
2014/12/10 职场文书
写给导师的自荐信
2015/03/06 职场文书
2015年学校教育教学工作总结
2015/04/22 职场文书
工程项目合作意向书
2015/05/08 职场文书
正则表达式拆分url实例代码
2022/02/24 Java/Android
Python安装及建立虚拟环境的完整步骤
2022/06/25 Servers
MySQL中TIMESTAMP类型返回日期时间数据中带有T的解决
2022/12/24 MySQL