正则表达式的贪婪模式、非贪婪模式、占有模式

文章目录

  • 一、Greediness(贪婪型)
    • (一)贪婪模式示例
    • (二)贪婪模式的匹配过程(贪婪模式的回溯)
  • 二、Reluctant(勉强型)
    • (一)非贪婪模式示例
    • (二)非贪婪模式的匹配过程
  • 三、Possessive(占有型)
    • (一)占有模式示例
    • (二)占用模式的匹配过程

一、Greediness(贪婪型)

贪婪模式,最大匹配,匹配优先。

Greediness 的模式下,会尽量大范围的匹配,直到匹配了整个内容,这时发现匹配不能成功时,开始回退缩小匹配范围,直到匹配成功。

默认情况下,所有的限定符都是贪婪模式,表示尽可能多的去捕获字符。

(一)贪婪模式示例

正则表达式:/<.+>/,这个正则表达式的含义:匹配以 < 为首,以 > 为尾,中间是 1 个或多个任意字符的字符串。
被查找的字符串:a<tr>aava </tr>abb
匹配的结果:<tr>aava </tr>

Java 代码举例如下:

String test = "a<tr>aava </tr>abb";
String reg = "<.+>";
System.out.println(test.replaceAll(reg, "###"));

说明:上面的 Java 代码会将字符串 a<tr>aava </tr>abb 中所有符合正则式的字符串替换为 ###,最后输出结果为:a###abb。其实 <tr></tr> 也符合正则式 /<.+>/,但是贪婪呀,因为被匹配的字符串还很长,所以会继续匹配下去,直到捕获到最多且匹配成功为止。

注意:正则表达式的限定符(量词)?+* 以及区间限定符 {n,m} 默认都是贪婪模式。

再举个例子:

String test = "foooood";
String reg ="o{1,}";
System.out.println(test.replaceAll(reg, "#"));

上面的 Java 代码会一次匹配全部的字符 o,什么意思?就是说整个正则表达式单次匹配成功中,会匹配尽可能多的字符,而 ooooo 是符合正则式 o{1,} 的,所以在单次匹配成功中就全部捕获了,所以最后输出的结果为:f#d。如果你想得到这样的结果:f#####d,应该怎么写表达式呢?那么表达式成功匹配一个 o 时,就算整个正则表达式匹配成功 1 次,那么成功匹配 5 个 o,就算整个正则式匹配成功了 5 次,这样就会执行 5 次替换,最后 ooooo 就会替换成 #####,我们看下面的示例。

String test = "foooood";
String reg ="o{1,}?";
System.out.println(test.replaceAll(reg, "#"));

在区间量词后添加个问号 ?,就是非贪婪模式,那么匹配了一个 o,就算正则式成功匹配一次,然后正则式又重新从正则式的第一个子表达式对被匹配的字符串已经成功匹配的下个字符开始继续匹配,直到无字符可匹配为止。

(二)贪婪模式的匹配过程(贪婪模式的回溯)

贪婪模式的正则表达式<.*>去匹配字符串"a<>aava</>abb",会匹配到"<>aava</>",下面说一下贪婪模式的具体匹配过程。

在这里插入图片描述
首先 <.*> 中的 < 获得控制权,尝试匹配字符串"a<>aava</>abb"中的第一个字符"a",匹配失败。继续尝试匹配第二个字符"<",匹配成功,将控制权交给 .*

.* 为贪婪模式,会尽可能多的匹配字符,会先去匹配第三个字符">",匹配成功,记录下一个回溯状态,继续匹配第四个字符"a",直到匹配到字符串结尾的最后一个字符"b"。字符串后没有字符了,.* 继续匹配失败,将控制权交给 >

> 尝试匹配字符串结尾失败,向前查找可回溯状态,控制权交给 .*.* 让出一个字符,也就是字符串结尾的"b",然后将控制权交给 >> 尝试匹配字符串结尾的"b",匹配失败,再次向前查找可回溯状态,将控制权交给 .*

重复以上过程,直到 .* 让出第十个字符">",> 匹配第十个字符">"成功,从而整个正则表达式匹配成功一次。< 继续从第十一个字符"a"开始匹配,但是直到字符串结束都没有匹配成功的,最终匹配结束。

可以看到,.* 会尽可能多的匹配字符,直到无法继续匹配,才会将控制权交给接下来的表达式。当接下来的表达式匹配失败后,.* 会让出之前匹配的字符,直到整个正则表达式匹配成功。

总结:贪婪模式的回溯,会让出已经匹配成功的字符给下一个正则式的表达式。吃太多了,别人没得吃,一点点吐出去给别人吃~

二、Reluctant(勉强型)

也叫 Laziness,懒惰型,懒惰模式,勉强模式,非贪婪模式,最小匹配,忽略优先。

Reluctant 的模式下,就是在匹配成功的前提下,尽可能少的匹配字符。

在限定词后增加 ?,则是非贪婪模式,表示尽可能少的去捕获字符。

例如:??*?+?{n,}?{n,m}?

(一)非贪婪模式示例

被查找的字符串:a<tr>aava </tr>abb

你希望匹配结果为:<tr>,就要使用表达式:/<.+?>/,但是从被查找的字符串可以知道,有两个地方匹配正则表达式,所以最终会匹配得到两个结果:<tr></tr>

Java 代码举例如下:

String test = "a<tr>aava </tr>abb";
String reg = "<.+>";
System.out.println(test.replaceAll(reg, "###"));

上面的 Java 代码会将字符串 a<tr>aava </tr>abb 中所有符合表达式的字符串替换为 ###,最后输出结果为:a###aava ###abb

(二)非贪婪模式的匹配过程

先举个例子:
正则式 <.+?> 去匹配字符串 a<>aava</>abb,会成功匹配到谁呢?四个选项:

A.<>
B.</>
C.<>aava</>
D.匹配失败

我相信很多人会选中选项 B,不过正确答案是 C。

想要理解为什么在非贪婪模式下,<.+?> 还是匹配了这么多字符,需要知道非贪婪模式下的匹配过程。
在这里插入图片描述
首先 <.+?> 中的 < 获得控制权,匹配字符串中的第一个字符"a",匹配失败。< 继续尝试匹配第二个字符"<",匹配成功。

接下来 .+? 获得控制权,. 可以匹配除换行符之外的任意一个字符,+ 表示一个或多个,? 表示非贪婪模式,即在成功的前提下尽量少的匹配字符,所以 .+? 会先去匹配成功一次,然后立刻就会将控制权交给正则表达式中的下一个。如果是贪婪模式,.+ 是不会匹配成功就早早地让出控制权的,而是会继续匹配下去,直到匹配失败了才把控制权让给正则表达式的下一个字符。

所以 .+? 获得控制权后,会先去匹配第三个字符">",成功后记录下回溯状态,立即将控制权交给表达式中的 >> 获得控制权后,会尝试匹配第四个字符"a",匹配失败,向前查找可回溯状态,于是 .+? 重新取得控制权,.+? 记录的回溯位置是第 3 个字符“>”,于是 .+? 会去匹配回溯位置的下一个字符,也就是第 4 个字符“a”,匹配成功后再次记录下回溯状态,然后再次将控制权交给 >> 获得控制权后,会尝试匹配第五个字符"a",结果匹配失败,再次向前查找可回溯状态…

就这样重复上述过程,直到 .+? 匹配到了第九个字符"/",将控制权交给 >> 匹配第十个字符">",终于匹配成功了,从而整个正则表达式匹配成功一次,记录下匹配结果。因为每个字符只能被正则匹配一次,所以 < 继续从第十一个字符"a"开始匹配,但是直到字符串结束都没有匹配成功的,最终匹配结束。

可以看到 .+? 会先尽可能少的匹配字符,优先将控制权交给接下来的表达式。但因为接下来的表达式一直匹配失败,.+? 不得不继续匹配字符。最终 .+? 的匹配内容是">aava</",并且进行了 6 次回溯。

总结:非贪婪模式的回溯,是被迫继续匹配下一个字符,再让出控制权。给别人吃,别人吃不了,只好自己吃掉。

三、Possessive(占有型)

占有模式,完全匹配模式。

在限定符后面添加 + 就成为“占有模式”,例如:?+*+++{n,}+{n,m}+

Possessive 模式与 Greediness 有一定的相似性,那就是都尽量匹配最大范围的内容,直到内容结束,但与 Greediness 不同的是,完全匹配不再回退尝试匹配更小的范围,也就是“不回溯”。

(一)占有模式示例

String test = "a<tr>aava </tr>abb";
String test2 = "<tr>";
String reg = "<.++>";
System.out.println(test.replaceAll(reg, "###"));
System.out.println(test2.replaceAll(reg, "###"));

以上的代码,输出结果为:a<tr>aava </tr>abb<tr>,也就是说字符串a<tr>aava </tr>abb<tr> 都不符合正则表达式 <.++>,那么这个表达式到底是怎么匹配的呢?

(二)占用模式的匹配过程

接下来看不回溯的占有模式是怎么匹配的。

占有模式的正则表达式 <.*+> 去匹配字符串"a<>aava</>abb",会匹配失败。具体的匹配过程如下。
在这里插入图片描述

前两步与贪婪模式的 <.*> 匹配过程基本一致。

< 获得控制权,尝试匹配字符串"a<>aava</>abb"中的第一个字符"a",匹配失败。继续尝试匹配第二个字符"<",匹配成功,将控制权交给 .*+

.*+ 也会尽可能多的匹配字符。不同的是,占有模式下表达式并不会记录回溯状态。.*+ 匹配到字符串结尾字符"b"后,没有字符了,于是继续匹配失败,将控制权交给 >

> 获得控制权后,尝试匹配字符串结尾,结尾无字符,匹配失败。因为没有回溯状态可查找,> 直接匹配失败,从而整个正则表达式 <.*+> 匹配失败。

带区间的类似 .{m,n}+ 也是不带回溯状态的,需要注意,具体匹配过程类似上文,就不详述了。

总结:把东西全部吃掉了,也不吐出来,结果导致别人没得吃

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/333785.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习pytorch--线性回归(二)

线性回归无框架实现线性回归的从零开始实现生成数据集(简单的人工构造)读取数据初始化模型参数定义模型定义损失函数定义优化算法训练模型小结完整代码(可直接运行)线性回归的从零开始实现 为了深入理解深度学习是如何工作的&#xff0c;本节不使用强大的深度学习框架&#xf…

乱码 设置界面_和平精英:压轴更新后BUG频出,设置界面崩盘,界面全白变乱码...

引言&#xff1a;陌瑾出品&#xff0c;争做精品&#xff01;大家好&#xff0c;我是你们的老朋友&#xff0c;陌瑾。和平精英作为当下比较热门的一款PVP即时战斗手游&#xff0c;在6月17日&#xff0c;海岛2.0版本也重装上阵&#xff0c;此次地图更新是和平精英游戏上线以来第1…

spring mvc教程_Spring MVC教程

spring mvc教程1.简介 作为企业Java开发人员&#xff0c;这项工作的主要重点之一是开发Web应用程序。 对于Web应用程序&#xff0c;后果还包括许多挑战。 具体来说&#xff0c;其中一些是状态管理&#xff0c;工作流和验证。 HTTP协议的无状态性质只会使事情变得更加复杂。 Spr…

正则表达式实例解读

文章目录正则式 a?正则式 ^\w\d正则式 (\d){4}|\1{2}正则式 \d{4}|\d{2}正则式 a? 正则式&#xff1a;a? 被匹配的字符串&#xff1a;a<>aava</>ab 看下面的 Java 代码&#xff1a; String test "a<>aava</>abb"; String reg "a…

深度学习pytorch--线性回归(三)

线性回归pytorch框架实现线性回归的简洁实现生成数据集读取数据定义模型初始化模型参数定义损失函数定义优化算法训练模型小结完整代码:线性回归的简洁实现 随着深度学习框架的发展&#xff0c;开发深度学习应用变得越来越便利。实践中&#xff0c;我们通常可以用比上一节更简…

smpp客户端_SMPP Java示例(客户端)

smpp客户端这篇文章通过创建一个简单的SMPP客户端向移动用户发送短信来提供SMPP Java示例&#xff0c;使用该客户端我们可以简单地提交以将消息发送给单个移动用户&#xff0c;也可以一次将消息广播给多个移动用户。另外&#xff0c;我们将验证交货收据。 出于客户端的目的&…

正则表达式的环视深度剖析

文章目录一、环视基础二、顺序环视匹配过程&#xff08;一&#xff09;顺序肯定环视匹配过程&#xff08;二&#xff09;顺序否定环视匹配过程三、逆序环视匹配过程&#xff08;一&#xff09;逆序环视基础&#xff08;二&#xff09;逆序肯定环视匹配过程1. 逆序表达式的长度固…

深度学习pytorch--softmax回归(一)

softmax回归 前几节介绍的线性回归模型适用于输出为连续值的情景。在另一类情景中&#xff0c;模型输出可以是一个像图像类别这样的离散值。对于这样的离散值预测问题&#xff0c;我们可以使用诸如softmax回归在内的分类模型。和线性回归不同&#xff0c;softmax回归的输出单元…

python比较excel表格内容并提取_利用python提取多张excel表数据并汇总到同一张新表中...

接上篇文章《如何用python实现excel中的vlookup功能&#xff1f;》&#xff0c;上篇说到&#xff0c;最近我在做一个小项目&#xff0c;也是用python操作excel解决财务审计工作上的一些问题&#xff0c;以便提高工作效率及其准确性。最终目的&#xff0c;刀哥是想做应收账款账龄…

阿帕奇跨域_阿帕奇齿轮泵

阿帕奇跨域Apache Gearpump是一个实时大数据流引擎。 它于2014年中期在GitHub上作为一个开源项目在英特尔构想&#xff0c;并于2016年3月8日进入Apache孵化。Gearpump的名称是对工程术语“齿轮泵”的指称&#xff0c;它是一个超级简单的泵&#xff0c;由以下组成只有两个齿轮&a…

正则表达式之 NFA 引擎匹配原理详解

文章目录一、为什么要了解引擎匹配原理二、正则表达式引擎三、预备知识&#xff08;一&#xff09;字符串组成&#xff08;二&#xff09;占有字符和零宽度&#xff08;三&#xff09;控制权和传动四、正则表达式简单匹本过程&#xff08;一&#xff09;基础匹配过程&#xff0…

阿帕奇跨域_阿帕奇光束

阿帕奇跨域Apache Beam是一个开放源代码统一模型&#xff0c;用于定义批处理和流数据并行处理管道。 使用一种开源的Beam SDK&#xff0c;您可以构建一个定义管道的程序。 然后&#xff0c;该管道由Beam支持的分布式处理后端之一执行&#xff0c;这些后端包括Apache Apex &…

unity 启动相机_Unity3D研究院之打开照相机与本地相册进行裁剪显示(三十三)...

最近做项目需要用到这个功能&#xff0c;就是在Unity中调用Android本地相册或直接打开摄像机拍照并且裁剪一部分用于用户头像&#xff0c;今天研究了一下&#xff0c;那么研究出成果了MOMO一定要分享给大家。Unity与Android的交互还有谁不会&#xff1f;&#xff1f; 如果有不会…

深度学习pytorch--MNIST数据集

图像分类数据集&#xff08;Fashion-MNIST&#xff09; 在介绍softmax回归的实现前我们先引入一个多类图像分类数据集。它将在后面的章节中被多次使用&#xff0c;以方便我们观察比较算法之间在模型精度和计算效率上的区别。图像分类数据集中最常用的是手写数字识别数据集MNIS…

html 元素的属性

全局属性 全局属性是可与所有 HTML 元素一起使用的属性。 事件属性 用来定义某个事件的操作的属性叫事件属性&#xff0c;例如&#xff0c;οnclick“script”&#xff0c;元素上发生鼠标点击时触发 click 事件&#xff0c;click 事件被触发就会执行对应的脚本代码。事件属性…

nosql和rdnms_用于SaaS和NoSQL的Jdbi

nosql和rdnms一个自然的接口&#xff0c;用于与CRM&#xff0c;ERP&#xff0c;会计&#xff0c;营销自动化&#xff0c;NoSQL&#xff0c;平面文件等基于Java的数据集成 Jdbi是用于JavaSQL便利库&#xff0c;它为JDBC提供更自然的Java数据库接口&#xff0c;该接口易于绑定到…

matlab 功率谱密度 汉宁窗_如何理解随机振动的功率谱密度?

一、随机信号和正太分布有什么关系&#xff1f; 二、时域、频域之间功率守恒&#xff1f; 三、自相关又是个什么玩意&#xff1f;作为一个工程师&#xff0c;很多人对随机振动看着熟悉&#xff0c;却又实际陌生。熟悉是因为几乎每个产品在出厂时都要求要做随机振动试验&#xf…

深度学习pytorch--softmax回归(二)

softmax回归的从零开始实现实验前思考获取和读取数据获取数据集查看数据集查看下载后的.pt文件查看mnist_train和mnist_test读取数据集查看数据迭代器内容初始化模型参数定义softmax函数定义模型定义损失函数计算分类准确率模型评价--准确率开始训练可视化总结完整代码实验前思…

HTML块级元素/块标签/块元素

文章目录块元素的特点块元素清单block level element. 块级元素想在同一行显示需浮动或者 display:inline。 块元素的特点 每个块级元素都是独自占一行&#xff0c;其后的元素也只能另起一行&#xff0c;并不能两个元素共用一行&#xff1b; 元素的高度、宽度、行高、顶边距、…

物联卡查询流量_电信物联卡官网是多少?如何快速查询流量信息?

高速率设备的使用场景需要用到5G&#xff0c;中速率LET-Cat1应用范围更广&#xff0c;而低速率则要靠窄带物联网NB-IOT去维护了。这三种网络制式全都与物联网息息相关&#xff0c;这就能知道为什么国家层面对物联网基础设施建设这么重视了。电信物联卡在智能化硬件中有优秀表现…