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 11 Python
python利用beautifulSoup实现爬虫
Sep 29 Python
横向对比分析Python解析XML的四种方式
Mar 30 Python
Python 转义字符详细介绍
Mar 21 Python
python网络爬虫学习笔记(1)
Apr 09 Python
python调用OpenCV实现人脸识别功能
May 25 Python
Django unittest 设置跳过某些case的方法
Dec 26 Python
详解Django模版中加载静态文件配置方法
Jul 21 Python
python+django+selenium搭建简易自动化测试
Aug 19 Python
聊聊python中的异常嵌套
Sep 01 Python
手把手教你从PyCharm安装到激活(最新激活码),亲测有效可激活至2089年
Nov 25 Python
python常量折叠基础知识点讲解
Feb 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
电脑硬件及电脑配置知识大全
2020/03/17 数码科技
配置最新的PHP加MYSQL服务器
2006/10/09 PHP
php 删除一个数组中的某个值.兼容多维数组!
2012/02/18 PHP
php解析html类库simple_html_dom(详细介绍)
2013/07/05 PHP
对于ThinkPHP框架早期版本的一个SQL注入漏洞详细分析
2014/07/04 PHP
如何修改Laravel中url()函数生成URL的根地址
2017/08/11 PHP
PHP递归实现汉诺塔问题的方法示例
2017/11/25 PHP
IE6图片加载的一个BUG解决方法
2010/07/13 Javascript
jquery控制listbox中项的移动并排序的实现代码
2010/09/28 Javascript
Javascript前端UI框架Kit使用指南之kitjs的对话框组件
2014/11/28 Javascript
使用jquery+CSS3实现仿windows10开始菜单的下拉导航菜单特效
2015/09/24 Javascript
javascript每日必学之多态
2016/02/23 Javascript
Node.js实用代码段之正确拼接Buffer
2016/03/17 Javascript
canvas绘图不清晰的解决方案
2017/02/28 Javascript
ES6正则的扩展实例详解
2017/04/25 Javascript
node通过npm写一个cli命令行工具
2017/10/12 Javascript
深入理解vue中slot与slot-scope的具体使用
2018/01/26 Javascript
基于JavaScript 实现拖放功能
2019/09/12 Javascript
vue+render+jsx实现可编辑动态多级表头table的实例代码
2020/04/01 Javascript
vue实现路由懒加载的3种方法示例
2020/09/01 Javascript
[02:04]2018DOTA2亚洲邀请赛Secret赛前采访
2018/04/03 DOTA
Python Web框架Flask下网站开发入门实例
2015/02/08 Python
浅析Python中return和finally共同挖的坑
2017/08/18 Python
基于python的字节编译详解
2017/09/20 Python
Python实现进程同步和通信的方法
2018/01/02 Python
浅谈Scrapy网络爬虫框架的工作原理和数据采集
2019/02/07 Python
Python切割图片成九宫格的示例代码
2020/03/10 Python
css3实现可拖动的魔方3d效果
2019/05/07 HTML / CSS
寻找完美的房车租赁:RVShare
2019/02/23 全球购物
幼儿园教师工作感言
2014/02/15 职场文书
党的群众路线教育实践活动个人对照检查材料(企业)
2014/11/05 职场文书
城管年度个人总结
2015/02/28 职场文书
经销商会议开幕词
2016/03/04 职场文书
导游词之昭君岛
2020/01/17 职场文书
JS如何实现基于websocket的多端桥接平台
2021/05/14 Javascript
python 命令行传参方法总结
2021/05/25 Python