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实现的各种排序算法代码
Mar 04 Python
python实现进程间通信简单实例
Jul 23 Python
Python编程中对super函数的正确理解和用法解析
Jul 02 Python
使用pyecharts无法import Bar的解决方案
Apr 23 Python
Python制作Windows系统服务
Mar 25 Python
Python列表list操作符实例分析【标准类型操作符、切片、连接字符、列表解析、重复操作等】
Jul 24 Python
python 高效去重复 支持GB级别大文件的示例代码
Nov 08 Python
使用Python制作简单的小程序IP查看器功能
Apr 16 Python
Python生成指定数量的优惠码实操内容
Jun 18 Python
Python : turtle色彩控制实例详解
Jan 19 Python
Python打包exe时各种异常处理方案总结
May 18 Python
使用pipenv管理python虚拟环境的全过程
Sep 25 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应用程序来获取Web服务器的状态信息
2006/10/09 PHP
PHP中break及continue两个流程控制指令区别分析
2011/04/18 PHP
解析php session_set_save_handler 函数的用法(mysql)
2013/06/29 PHP
PHP中exec与system用法区别分析
2014/09/22 PHP
swoole_process实现进程池的方法示例
2018/10/29 PHP
PHP面向对象程序设计之接口的继承定义与用法详解
2018/12/20 PHP
PHP解密支付宝小程序的加密数据、手机号的示例代码
2021/02/26 PHP
灵活应用js调试技巧解决样式问题的步骤分享
2012/03/15 Javascript
JSON+JavaScript处理JSON的简单例子
2013/03/20 Javascript
Javascript中 关于prototype属性实现继承的原理图
2013/04/16 Javascript
js与运算符和或运算符的妙用
2014/02/14 Javascript
Jquery对select的增、删、改、查操作
2015/02/06 Javascript
asp知识整理笔记3(问答模式)
2015/09/27 Javascript
javascript中的try catch异常捕获机制用法分析
2016/12/14 Javascript
详解jQuery停止动画——stop()方法的使用
2016/12/14 Javascript
vue组件实例解析
2017/01/10 Javascript
jQuery插件zTree实现获取当前选中节点在同级节点中序号的方法
2017/03/08 Javascript
100行代码理解和分析vue2.0响应式架构
2017/03/09 Javascript
深入理解vue Render函数
2017/07/19 Javascript
JavaScript实现图片伪异步上传过程解析
2020/04/10 Javascript
vue.js实现h5机器人聊天(测试版)
2020/07/16 Javascript
layui使用及简单的三级联动实现教程
2020/12/01 Javascript
Python 普通最小二乘法(OLS)进行多项式拟合的方法
2018/12/29 Python
Selenium+Python 自动化操控登录界面实例(有简单验证码图片校验)
2019/06/28 Python
python模块hashlib(加密服务)知识点讲解
2019/11/25 Python
matplotlib绘制多个子图(subplot)的方法
2019/12/03 Python
浅谈在django中使用redirect重定向数据传输的问题
2020/03/13 Python
谈谈对css属性box-sizing的了解
2017/01/04 HTML / CSS
利用html5的websocket实现websocket聊天室
2013/12/12 HTML / CSS
质量主管工作职责
2014/09/26 职场文书
2015年语文教师工作总结
2015/05/25 职场文书
婚庆开业庆典主持词
2015/06/30 职场文书
MySQL Innodb关键特性之插入缓冲(insert buffer)
2021/04/08 MySQL
Python 循环读取数据内存不足的解决方案
2021/05/25 Python
Python 中random 库的详细使用
2021/06/03 Python
详解OpenCV获取高动态范围(HDR)成像
2022/04/29 Python