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中使用支持向量机(SVM)算法
Dec 26 Python
TensorFlow实现随机训练和批量训练的方法
Apr 28 Python
python中scikit-learn机器代码实例
Aug 05 Python
python3用PIL把图片转换为RGB图片的实例
Jul 04 Python
python3 实现调用串口功能
Dec 26 Python
浅谈django框架集成swagger以及自定义参数问题
Jul 07 Python
Python的scikit-image模块实例讲解
Dec 30 Python
pytorch DataLoader的num_workers参数与设置大小详解
May 28 Python
Python list列表删除元素的4种方法
Nov 01 Python
Python用tkinter实现自定义记事本的方法详解
Mar 31 Python
Python 全局空间和局部空间
Apr 06 Python
python manim实现排序算法动画示例
Aug 14 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
Laravel的throttle中间件失效问题解决方法
2016/10/09 PHP
PHP性能分析工具xhprof的安装使用与注意事项
2017/12/19 PHP
Laravel使用原生sql语句并调用的方法
2019/10/09 PHP
Ruffy javascript 学习笔记
2009/11/30 Javascript
IE图片缓存document.execCommand(&quot;BackgroundImageCache&quot;,false,true)
2011/03/01 Javascript
jQuery中live方法的重复绑定说明
2011/10/21 Javascript
两个数组去重的JS代码
2013/12/04 Javascript
JavaScript中的Math.SQRT1_2属性使用简介
2015/06/14 Javascript
javascript数据结构之二叉搜索树实现方法
2015/11/25 Javascript
JS JSOP跨域请求实例详解
2016/07/04 Javascript
jQuery插件ajaxFileUpload使用实例解析
2016/10/19 Javascript
vue-router跳转页面的方法
2017/02/09 Javascript
JavaScript ES6中export、import与export default的用法和区别
2017/03/14 Javascript
Angular2.js实现表单验证详解
2017/06/23 Javascript
Angular中自定义Debounce Click指令防止重复点击
2017/07/26 Javascript
微信小程序实时聊天WebSocket
2018/07/05 Javascript
详解Webpack多环境代码打包的方法
2018/08/03 Javascript
JavaScript模板引擎应用场景及实现原理详解
2018/12/14 Javascript
babel7.x和webpack4.x配置vue项目的方法步骤
2019/05/12 Javascript
JS前端广告拦截实现原理解析
2020/02/17 Javascript
在react项目中使用antd的form组件,动态设置input框的值
2020/10/24 Javascript
Vue自定义表单内容检查rules实例
2020/10/30 Javascript
vue 判断页面是首次进入还是再次刷新的实例
2020/11/05 Javascript
[12:29]《一刀刀一天》之DOTA全时刻19:蝙蝠骑士田伯光再度不举
2014/06/10 DOTA
[07:09]2014DOTA2国际邀请赛-Newbee再次发威成功晋级决赛
2014/07/19 DOTA
python使用in操作符时元组和数组的区别分析
2015/05/19 Python
酷! 程序员用Python带你玩转冲顶大会
2018/01/17 Python
深入浅析Python获取对象信息的函数type()、isinstance()、dir()
2018/09/17 Python
pygame游戏之旅 添加碰撞效果的方法
2018/11/20 Python
Python3 实现文件批量重命名示例代码
2019/06/03 Python
用Python识别人脸,人种等各种信息
2019/07/15 Python
python装饰器实现对异常代码出现进行自动监控的实现方法
2020/09/15 Python
详解HTML5中的标签
2015/06/19 HTML / CSS
反邪教标语
2014/06/23 职场文书
七年级作文之雪景
2019/11/18 职场文书
导游词之安徽醉翁亭
2020/01/10 职场文书