正则表达式量词与贪婪的使用详解

目录
  • 0.写在前面
  • 1.量词
  • 2.贪婪模式前传
    • 2.1 使用 a+ 进行匹配
    • 2.2 使用 a* 进行匹配
  • 3.贪婪模式
  • 4.非贪婪模式
  • 5.独占模式
    • 5.1 贪婪匹配过程
    • 5.2 非贪婪匹配过程
    • 5.3 独占匹配过程
  • 6.写在最后

0.写在前面

在上一篇文章中,我们学习了正则的一些基础元字符,相信大家都已经忘却的差不多了,可以点击上面的链接再温习下。

今天我们一起来学习下正则中量词的三种匹配模式,贪婪模式、非贪婪模式、独占模式,这些模式会改变正则中量词的匹配行为,是每次贪婪的匹配到更多呢,还是不贪婪见好就收呢,如果不了解这些,我们写出的正则很可能是错误的,甚至会引发严重的线上性能问题。

1.量词

本篇文章所讲的内容和量词关系比较密切,先回顾下:

我们还可以用 {m,n} 的方式来表示 * + ? 这3种元字符:

元字符 同义表示方法 示例
* {0,} ab*
可以匹配
a 或者 abb
+ {1,} ab+
可以匹配
ab 或者 abb
但不能匹配 a
? {0,1} ab?
可以匹配 a 或者 ab
但不能匹配 abb

2.贪婪模式前传

在正则中,表示次数的量词默认是贪婪的,在贪婪模式下,会尽可能最大长度的去匹配目标字符串,我们用正则 a+a* 来匹配字符串 aaabb 测试一下。

2.1 使用 a+ 进行匹配

可以看到只匹配到了1个结果 aaa

对应的 Python 代码如下:

import re

print(re.findall(r'a+', 'aaabb'))

输出:['aaa']

2.2 使用 a* 进行匹配

可以看到匹配到了4个结果,其中还有3个是空字符串

对应的 Python 代码如下:

import re

print(re.findall(r'a*', 'aaabb'))

输出:['aaa', '', '', '']

为什么会匹配到空字符串呢?因为星号(*)代表匹配0到多次,匹配0次就是空字符串,那前面还有个 aaa 呢,为什么 aaa 之间的空字符串没有被匹配到?

这就引入到了我们今天要讲的,贪婪模式与非贪婪模式,从字面上很好理解,贪婪模式就是尽可能多的匹配,非贪婪模式就是尽可能少的匹配。

3.贪婪模式

一起来分析下上面正则 a* 的匹配过程:

字符串 a a a b b 空字符串
下标 0 1 2 3 4 5
匹配 开始 结束 说明 匹配内容
第一次 0 3 到第一个字母b发现不匹配,输出aaa aaa
第二次 3 3 匹配剩下的bb,发现匹配不上,输出空字符串 空字符串
第三次 4 4 匹配剩下的b,发现匹配不上,输出空字符串 空字符串
第四次 5 5 匹配剩下的空字符串,输出空字符串 空字符串

a* 在匹配字符串 aaabb 时,会尽可能多的把前面的 a 都匹配上,直到第一个字母 b 不满足要求为止,匹配上3个 a,后面每次匹配的都是空字符串。

看到这里,相信你已经对贪婪模式有了更深的印象,贪婪模式的特点就是尽可能进行最大长度匹配,就是有多少要多少,下面我们在一起来看下与它完全相反的匹配模式。

4.非贪婪模式

上面讲完了贪婪模式,贪婪模式是尽可能最大长度匹配,非贪婪模式就是尽可能最小长度匹配,在量词的后面加一个问号(?),就成了非贪婪模式,比如 a*?

对应的 Python 代码如下:

import re

// 贪婪匹配
print(re.findall(r'a*', 'aaabb'))

输出:['aaa', '', '', '']

// 非贪婪匹配
print(re.findall(r'a*?', 'aaabb'))

输出:['', 'a', '', 'a', '', 'a', '', '', '']

学完了贪婪模式与非贪婪模式,你可能会问,我什么情况下会用到呢,下面举个栗子感受下:

需求是查找一段字符串中,所有双引号括起来的内容,上面使用贪婪匹配与非贪婪匹配的对比,差别很明显对吧。

5.独占模式

不管是贪婪模式,还是非贪婪模式,匹配过程中都需要发生回溯才能完成想要的功能,但是在有一些场景,我们不需要回溯,匹配不上直接返回失败就可以了,因此正则匹配中还有另外一种模式,独占模式,它和贪婪模式很像,但匹配过程中不会发生回溯,在一些使用场景中性能会更好。

先来讲讲什么是回溯,再举个栗子,有一个正则表达式和目标字符串,我们分别看下在三种匹配模式下都发生了什么:

5.1 贪婪匹配过程

正则表达式:ab{1,3}c

目标字符串:abbc

在匹配时,b{1,3} 会尽可能长的去匹配目标字符串,匹配完 abb 之后,因为要尽可能长的匹配(3个 b),目标字符串中的c就会匹配不上,这个时候会发生向前回溯,吐出当前字符 c,用正则中的 c 去匹配,匹配成功。

import regex

print(regex.findall(r'ab{1,3}c', 'abbc'))

输出:['abbc']

5.2 非贪婪匹配过程

正则表达式:ab{1,3}?c

目标字符串:abbc

在匹配时,b{1,3} 会尽可能短的去匹配目标字符串,匹配完 ab 之后,会直接用正则 c 去匹配目标字符串剩下的 b,匹配不上,发生向前回溯,重新用正则 b{1,3} 匹配 目标字符串剩下的 b,然后正则 c 匹配 目标字符串剩下的 c,匹配成功。

import regex

print(regex.findall(r'ab{1,3}?c', 'abbc'))

输出:['abbc']

5.3 独占匹配过程

在量词后面加上 + 就是独占模式。

正则表达式:ab{1,2}+bc

目标字符串:abbc

在匹配时,b{1,2} 会尽可能长的去匹配目标字符串,匹配完 abb 之后,会用正则 b 匹配目标字符串剩下的 c,匹配不上,不回溯,匹配失败。

import regex

print(regex.findall(r'ab{1,2}+bc', 'abbc'))

输出:[]

6.写在最后

最后在总结下上面讲到的内容:

到这里,正则表达式的量词与贪婪就讲完了,如果有问题可以给我留言评论,谢谢。

正则表达式在线校验工具:https://regex101.com/

到此这篇关于正则表达式量词与贪婪的使用详解的文章就介绍到这了,更多相关正则表达式 量词与贪婪内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2021-07-26

浅谈php正则表达式中的非贪婪模式匹配的使用

通常我们会这么写: 复制代码 代码如下: $str = "http://www.baidu/.com?url=www.sina.com/"; preg_match("/http:(.*)com/", $str, $matches); print_r($matches); 结果: 复制代码 代码如下: Array ( [0] => http://www.baidu/.com?url=www.sina.com [1] => //www.baidu/.com?

正则表达式之 贪婪与非贪婪模式详解(概述)

1 概述 贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配,而非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配.非贪婪模式只被部分NFA引擎所支持. 属于贪婪模式的量词,也叫做匹配优先量词,包括: "{m,n}"."{m,}"."?"."*"和"+". 在一些使用NFA引擎的语言中,在匹配优先量词后加上"?",即变成属于非

小议正则表达式效率 贪婪、非贪婪与回溯

先扫盲一下什么是正则表达式的贪婪,什么是非贪婪?或者说什么是匹配优先量词,什么是忽略优先量词? 好吧,我也不知道概念是什么,来举个例子吧. 某同学想过滤之间的内容,那是这么写正则以及程序的. 复制代码 代码如下: $str = preg_replace('%<script>.+?</script>%i','',$str);//非贪婪 看起来,好像没什么问题,其实则不然.若 复制代码 代码如下: $str = '<script<script>alert(docume

[正则表达式]贪婪模式与非贪婪模式

复制代码 代码如下: /**     **   author: site120     **   function : get script part from html document     **/     var loadJs = function(str , delayTime)      {          var delayTime = delayTime || 100;          var regExp_scriptTag = new RegExp("<\\s*sc

正则表达式(regex) 贪婪模式、懒惰模式使用方法

正则表达式贪婪匹配模式,对于初学者,往往也很容易出错.有时候需要匹配一个段代码内容,发现匹配与想要不一致.发现原来,跟贪婪模式有关系.如下,我们看下例子: 什么是贪婪模式 字符串有: "<h3>abd</h3><h3>bcd</h3>",我们想匹配<h3>-</h3>内容,正则表达式如下: 1.h3开头与结尾,"<h3>待添加</h3>" <h3></h

正则表达式单行、多行模式简介(使用说明)

继上几篇正则表达式相关说明(详情:正则表达式 ),我们今天继续讨论下,它的单行,多行模式使用,及容易出现错误地方.单行,多行模式,都是正则表达式的模式修饰符里面出现的参数.目前常用正则表达式都有该使用选项,如:javascript 正则表达式,一般是:"/正则表达式匹配字符/修饰符" ,最后一个"/" 后面是修饰符.然后,php也是类似的,c#,python等,一般调用正则表达式的匹配函数,都有一个另外选项的,设置模式. 单行.多行模式容易出现理解错误 为什么说,容

详解正则表达式的贪婪模式与非贪婪模式

什么是正则表达式的贪婪与非贪婪匹配 如:String str="abcaxc"; Patter p="ab*c"; 贪婪匹配:正则表达式一般趋向于最大长度匹配,也就是所谓的贪婪匹配.如上面使用模式p匹配字符串str,结果就是匹配到:abcaxc(ab*c). 非贪婪匹配:就是匹配到结果就好,就少的匹配字符.如上面使用模式p匹配字符串str,结果就是匹配到:abc(ab*c). 下面通过实例代码看下正则表达式的贪婪模式与非贪婪模式,具体内容如下所示: 贪婪模式:能匹配

JS中正则表达式只有3种匹配模式(没有单行模式)详解

JS正则表达式对象模式仅有如下三种:  g (全文查找出现的所有 pattern) i (忽略大小写) m (多行查找) 即没有单行匹配模式,Singleline(单行模式):更改.的含义,使它与每一个字符匹配(包括换行符\n). 如java中 String regex = "(?s)(?<=interface).{0,500}(shutdown)";---------"."表示在一行. 但可以采用[\d\D]或[\w\W]或[\s\S]或(.|\s)*?来解

Android 实现夜间模式的快速简单方法实例详解

ChangeMode 项目地址:ChangeMode Implementation of night mode for Android. 用最简单的方式实现夜间模式,支持ListView.RecyclerView. Preview Usage xml android:background="?attr/zzbackground" app:backgroundAttr="zzbackground"//如果当前页面要立即刷新,这里传入属性名称 比如 R.attr.zzb

Joomla实现组件中弹出一个模式(modal)窗口的方法

本文实例讲述了Joomla实现组件中弹出一个模式(modal)窗口的方法.分享给大家供大家参考,具体如下: 最关键的JS在 /media/system/js/modal.js .有以下两种方式都可以实现,修改的都是扩展组件的模板文件default.php. 方式一: <?php JHTML::_('behavior.modal', 'a.modal');?> <a rel="{handler: 'iframe', size: {x: 570, y: 400}}" hr

C#实现单件模式的三种常用方法

本文实例讲述了C#实现单件模式的三种常用方法.分享给大家供大家参考.具体分析如下: 单件模式是一种设计模式,即保持同时只能创建一个实例,下面列出了C#实现单件模式的三种方法 方法1 public sealed Class Singleton { private static ReadOnly Singleton instance = new Singleton(); private Singleton(){} public static Singleton Instance { get { re

Python读写文件模式和文件对象方法实例详解

本文实例讲述了Python读写文件模式和文件对象方法.分享给大家供大家参考,具体如下: 一. 读写文件模式 利用open() 读写文件时,将会返回一个 file 对象,其基本语法格式如:  open ( filename, mode) 其中,filename变量是一个包含了你要访问的文件名称的字符串值.而mode决定了你打开文件的模式:只读,写入,追加等.所有可取值见如下的完全列表. 注:这个参数是非强制的,默认文件访问模式为只读模式(r) 例如,我们现在将一个字符串写入到test.txt文件中

python获取指定字符串中重复模式最高的字符串方法

给定一个字符串,如何得到其中重复模式最高的子字符串,我采用的方法是使用滑窗机制,对给定的字符串切分,窗口的大小从1增加到字符串长度减1,将所有的得到的切片统计结果,在这里不考虑单个字符的重复模式,好了,很简单看具体实现: #!usr/binenv python #encoding:utf-8 ''' __Author__:沂水寒城 统计一个给定字符串中重复模式数量得到最高重复模式串 ''' def slice(num_str,w): ''' 对输入的字符串滑窗切片返回结果列表 ''' resul