Python正则表达式教程之三:贪婪/非贪婪特性

作者:一根笨茄子 时间:2023-08-14 20:20:12 

之前已经简单介绍了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'>

来源:http://blog.guoyb.com/2017/03/01/python-regex-3/

标签:python,正则表达式,贪婪/非贪婪特性
0
投稿

猜你喜欢

  • mysql 之通过配置文件链接数据库

    2024-01-17 13:32:28
  • N年前的JAVASCRIPT笔记

    2009-01-07 12:40:00
  • golang编程入门之http请求天气实例

    2024-05-09 09:32:00
  • 关于401状态码的含义和处理方式

    2023-03-16 01:03:08
  • Python 堆叠柱状图绘制方法

    2022-05-15 01:39:00
  • MySQL安全性指南 (2)

    2010-07-26 13:26:00
  • ASP的错误代码都有哪些?

    2009-10-28 18:15:00
  • vue+element-ui+ajax实现一个表格的实例

    2024-04-10 10:34:27
  • 手写Vue2.0 数据劫持的示例

    2024-05-22 10:43:17
  • Windows系统下mysql5.7.21安装详细教程

    2024-01-21 17:26:38
  • 详解MySql基本查询、连接查询、子查询、正则表达查询

    2024-01-25 18:20:55
  • sql注入与转义的php函数代码

    2023-07-16 11:20:15
  • Vue3新属性之css中使用v-bind的方法(v-bind in css)

    2024-05-28 16:01:07
  • CSS Frameworks的概念

    2008-01-23 18:41:00
  • 基于ORA-19815闪回空间爆满问题的处理方法

    2024-01-21 03:35:04
  • Python程序设计入门(3)数组的使用

    2023-07-20 07:11:15
  • MYSQL事务的隔离级别与MVCC

    2024-01-20 10:59:48
  • javascript 版 Bad Apple 字符动画

    2010-01-28 12:19:00
  • Bootstrap 模态对话框只加载一次 remote 数据的完美解决办法

    2023-08-06 15:58:18
  • ASP获取ACCESS数据库的表名以及表名对应的字段名和字段类型

    2009-12-25 18:57:00
  • asp之家 网络编程 m.aspxhome.com