正则之环视

正则之环视

regex

  • 1.环视基础
  • 2.示例
    • 至少包含
    • 不重复
    • 分隔数字
    • 标签
  • 3.环视匹配原理
    • 顺序环视匹配过程
    • 逆序环视匹配过程
  • 4. 环视应用

参考:

正则基础之 环视 Lookaround

正则应用之 逆序环视探索

正则匹配原理之 逆序环视深入

1.环视基础

环视基础
表达式 说明
(?<=Expression) 逆序肯定环视,表示所在位置左侧能够匹配Expression
(?<!Expression) 逆序否定环视,表示所在位置左侧不能匹配Expression
(?=Expression) 顺序肯定环视,表示所在位置右侧能够匹配Expression
(?!Expression) 顺序否定环视,表示所在位置右侧不能匹配Expression

顺序环视相对是简单的,而逆序环视相对是复杂的

  • JavaScript中只支持顺序环视,不支持逆序环视。
  • Java中虽然顺序环视和逆序环视都支持,但是逆序环视只支持长度确定的表达式,逆序环视中量词只支持?,不支持其它长度不定的量词。

2.示例

至少包含

密码由8到16位长度的英文字母、数字,且至少包含一个英文字母

顺序肯定环视:^(?=[0-9]*+[a-zA-Z])[a-zA-Z0-9]{8,16}$

密码由8到16位长度的英文字母、数字和特殊字符,且至少包含一个英文字母,一个数字,一个特殊字符,不能包含空格

顺序肯定环视:^(?=[^a-zA-Z]*+[a-zA-Z])(?=[^0-9]*+[0-9])(?=[a-zA-Z0-9]*+[^a-zA-Z0-9])\S{8,16}$

不重复

由字母、数字、特殊字符组合的8至16位长度,只能包含一次wifi

顺序否定环视:^(?!\S*?wifi\S*wifi)\S{8,16}$

分隔数字

一串纯数字,从右开始每3位加逗号,如134545756变为134,545,756

逆序肯定环视:(?<=\d)(?=(?:\d\d\d)+$)

说明:(?<=\d)是为了保证左侧第一个必须为数字

一串以$结尾的数字,从右开始每3位加逗号,如134545756$变为134,545,756$

逆序肯定环视:(?<=\d)(?=(\d\d\d)+(?!\d))

需求:数字格式化成用“,”的货币格式。

java8在逆序环视中,不支持无限字符数量的匹配量词,如、+*

正则表达式:(?<=\d)(?<!\.\d{0,100})(?=(?:\d{3})+(?:\.\d+|$))

标签

需求:匹配除<p…></p>之外的其余标签,如:aa<p>one</p>bb<div>two</div>cc

正则表达式:<(?!/?p\b)[^>]+>

需求:匹配div标签之间的内容,如:<div>a test</div>

正则表达式:(?<=<div>)[^<]+(?=</div>)

3.环视匹配原理

匹配位置

顺序环视匹配过程

  • 对于顺序肯定环视(?=Expression)来说,当子表达式Expression匹配成功时,(?=Expression)匹配成功,并报告(?=Expression)匹配当前位置成功。
  • 对于顺序否定环视(?!Expression)来说,当子表达式Expression匹配成功时,(?!Expression)匹配失败;当子表达式Expression匹配失败时,(?!Expression)匹配成功,并报告(?!Expression)匹配当前位置成功。

源字符串:aa<p>one</p>bb<div>two</div>cc

正则表达式:<(?!/?p\b)[^>]+>

这个正则的意义就是匹配除<p…></p>之外的其余标签。

匹配过程:

  1. 首先由字符<取得控制权,从位置0开始匹配,由于<匹配a失败,在位置0处整个表达式匹配失败,第一次迭代匹配失败,正则引擎向前传动,由位置1处开始尝试第二次迭代匹配。
  2. 重复以上过程,直到位置2,<匹配<成功,控制权交给(?!/?p\b)(?!/?p\b)子表达式取得控制权后,进行内部子表达式的匹配。首先由/?取得控制权,尝试匹配p失败,进行回溯,不匹配,控制权交给p;由p来尝试匹配p,匹配成功,控制权交给\b;由\b来尝试匹配位置4,匹配成功。此时子表达式匹配完成,/?p\b匹配成功,那么环视表达式(?!/?p\b)就匹配失败。在位置2处整个表达式匹配失败,新一轮迭代匹配失败,正则引擎向前传动,由位置3处开始尝试下一轮迭代匹配。
  3. 在位置8处也会遇到一轮/?p\b匹配/p成功,而导致环视表达式(?!/?p\b)匹配失败,从而导致整个表达式匹配失败的过程。
  4. 重复以上3过程,直到位置14,<匹配<成功,控制权交给(?!/?p\b)/?尝试匹配d失败,进行回溯,不匹配,控制权交给p;由p来尝试匹配d,匹配失败,已经没有备选状态可供回溯,匹配失败。此时子表达式匹配完成,/?p\b匹配失败,那么环视表达式(?!/?p\b)就匹配成功。匹配的结果是位置15,然后控制权交给[^>]+;由[^>]+从位置15进行尝试匹配,可以成功匹配到div,控制权交给>;由>来匹配>

    此时正则表达式匹配完成,报告匹配成功。匹配结果为<div>,开始位置为14,结束位置为19。其中<匹配<(?!/?p\b)匹配位置15,[^>]+匹配字符串div>匹配>

逆序环视匹配过程

  • 对于逆序肯定环视(?<=Expression)来说,当子表达式Expression匹配成功时,(?<=Expression)匹配成功,并报告(?<=Expression)匹配当前位置成功。
  • 对于逆序否定环视(?<!Expression)来说,当子表达式Expression匹配成功时,(?<!Expression)匹配失败;当子表达式Expression匹配失败时,(?<!Expression)匹配成功,并报告(?<!Expression)匹配当前位置成功;
  • 顺序环视尝试匹配的起点是确定的,就是当前位置,而匹配的终点是不确定的。逆序环视匹配的起点是不确定的,是当前位置左侧某一位置,而匹配的终点是确定的,就是当前位置。
  • 所以顺序环视相对是简单的,而逆序环视相对是复杂的。这也就是为什么大多数语言和工具都提供了对顺序环视的支持,而只有少数语言提供了对逆序环视支持的原因。
  • JavaScript中只支持顺序环视,不支持逆序环视。
  • Java中虽然顺序环视和逆序环视都支持,但是逆序环视只支持长度确定的表达式,逆序环视中量词只支持?,不支持其它长度不定的量词。
  • 目前只有.NET中支持不确定长度的逆序环视。

源字符串:<div>a test</div>

正则表达式:(?<=<div>)[^<]+(?=</div>)

这个正则的意义就是匹配<div></div>标签之间的内容,而不包括<div></div>标签本身。

匹配过程:

  1. 首先由(?<=<div>)取得控制权,从位置0开始匹配,由于位置0是起始位置,左侧没有任何内容,所以<div>必然匹配失败,从而环视表达式(?<=<div>)匹配失败,导致整个表达式在位置0处匹配失败。第一轮迭代匹配失败,正则引擎向前传动,由位置1处开始尝试第二次迭代匹配。
  2. 直到传动到位置5,(?<=<div>)取得控制权,向左查找5个位置,由位置0开始匹配,由<div>匹配<div>成功,从而(?<=<div>)匹配成功,匹配的结果为位置5,控制权交给[^<]+[^<]+从位置5开始尝试匹配,匹配a test成功,控制权交给(?=</div>);由</div>匹配</div>成功,从而(?=</div>)匹配成功,匹配结果为位置11。
  3. 此时正则表达式匹配完成,报告匹配成功。匹配结果为a test,开始位置为5,结束位置为11。其中(?<=<div>)匹配位置5,[^<]+匹配a test(?=</div>)匹配位置11。
  4. 逆序否定环视的匹配过程与上述过程类似,区别只是当Expression匹配失败时,逆序否定表达式(?<!Expression)才匹配成功。

4. 环视应用

需求:数字格式化成用,的货币格式。

正则表达式:(?<=\d)(?<!\.\d*)(?=(?:\d{3})+(?:\.\d+|$))

实现分析:

首先根据需求可以确定是把一些特定的位置替换为“,”,接下来就是分析并找到这些位置的规律,并抽象出来以正则表达式来表示。

1、这个位置的左侧必须为数字

2、这个位置右侧到出现.或结尾为止,必须是数字,且数字的个数必须为3的倍数

3、这个位置左侧相隔任意个数字不能出现.

由以上三条,就可以完全确定这些位置,只要实现以上三条,组合一下正则表达式就可以了。

根据分析,最终匹配的结果是一个位置,所以所有子表达式都要求是零宽度。

1、是对当前所在位置左侧附加的条件,所以要用到逆序环视,因为要求必须出现,所以是肯定的,符合这一条件的子表达式即为(?<=\d)

2、是对当前所在位置右侧附加的条件,所以要用到顺序环视,也是要求出现,所以是肯定的,是数字,且个数为3的倍数,即(?=(?:\d{3})*),到出现.或结尾为止,即(?=(?:\d{3})*(?:\.|$))

3、是对当前所在位置左侧附加的条件,所以要用到逆序环视,因为要求不能出现,所以是否定的,即(?<!\.\d*)

因为零宽度的子表达式是非互斥的,最后匹配的都是同一个位置,所以先后顺序是不影响最后的匹配结果的,可以任意组合,只是习惯上把逆序环视写在左侧,顺序环视写在右侧。

时间: 2025-01-14 09:04:00

正则之环视的相关文章

JS 正则中环视(断言)应用 -- 数字千分符

介绍一下顺序环视 (?=...) 和逆序环视 (?<=...) 方便不想看长文的人,如果在支持 ES2018 的环境中整数可以这样使用: String(12345678).replace(/(?<=\d)(?=(\d{3})+\b)/g, ',') // "12,345,678" 其中最关键的是肯定顺序环视(?=...),也叫零宽度正预测先行断言.添加千分符麻烦的地方在于只有在从右到左 3 的倍数的位数和前面的数字中间需要添加逗号而正则是从左到右匹配的,这时候就需要用到顺序

深入理解正则表达式环视的概念与用法

在<深入理解正则表达式高级教程-环视>中已经对环视做了简单的介绍,但是,可能还有一些读者比较迷惑,今天特意以专题的形式,深入探讨一下正则表达式的环视的概念与用法. 深入理解正则表达式环视的概念与用法 一.环视的概念 (一)环视概念与匹配过程示例 示例一:简单环视匹配过程 (二)什么是消耗正则的匹配字符? 示例二:一次匹配消耗匹配字符匹配过程 示例三:多次匹配消耗匹配字符匹配过程 二.环视的类型 (一)肯定和否定 (二)顺序和逆序 · 两种类型名称组合 · 四种组合的用法 四种组合正则与环视的摆

正则基础之 环视

1 环视基础 环视只进行子表达式的匹配,不占有字符,匹配到的内容不保存到最终的匹配结果,是零宽度的.环视匹配的最终结果就是一个位置. 环视的作用相当于对所在位置加了一个附加条件,只有满足这个条件,环视子表达式才能匹配成功. 环视按照方向划分有顺序和逆序两种,按照是否匹配有肯定和否定两种,组合起来就有四种环视.顺序环视相当于在当前位置右侧附加一个条件,而逆序环视相当于在当前位置左侧附加一个条件. 表达式 说明 (?<=Expression) 逆序肯定环视,表示所在位置左侧能够匹配Expressio

正则基础之——环视(Lookaround)

1 环视基础 环视只进行子表达式的匹配,不占有字符,匹配到的内容不保存到最终的匹配结果,是零宽度的.环视匹配的最终结果就是一个位置. 环视的作用相当于对所在位置加了一个附加条件,只有满足这个条件,环视子表达式才能匹配成功. 环视按照方向划分有顺序和逆序两种,按照是否匹配有肯定和否定两种,组合起来就有四种环视.顺序环视相当于在当前位置右侧附加一个条件,而逆序环视相当于在当前位置左侧附加一个条件. 表达式 说明 (?<=Expression) 逆序肯定环视,表示所在位置左侧能够匹配Expressio

正则念念碎

正则表达式就原理来讲,只有一点点东东,就是一个状态机,只能用在上下文无关文法的环境. 但是它使用还是非常灵活的,那些厉害的,能够玩出花来,工作效率提高很多. 1.常见正则表达式符号 符号 描述 示例  literal 匹配文本字符串的字面值literal   foo  re1|re2 匹配表达式re1或者表达式re2  foo|bar  . 匹配除了(\n)之外的任何字符  b.b  ^ 匹配字符串起始的部分  ^Dear  $ 匹配字符串的结束部分  /bin/*sh$  * 匹配0次或者多次

正则学习(1)--- 基本规则总结

在正则表达式的使用上,俺一直在打游击,是时候来个总结了.由于愚笨等不可抗拒的原因,只能选简单的说,只写下对ASCII编码字符的匹配和php相关的,其他的Unicode的和其他不同流派的,以后碰到了再学习下就行,应付平常的应该够了. 首先需要接受正则的概念,它是用来寻找文本的一种规则,简单的文本检索,比如字符串查找strpos,只是简单的查找某一串字符的出现,只要稍微变动下需求,比如要查找这样5个字符,前面两个是数字,后面3个是字母,且忽略大小写,如果单纯用字符串查找等方法做,显得很麻烦,而用正则

.NET正则基础——.NET正则类及方法应用

1        概述 初学正则时,对于Regex类不熟悉,遇到问题不知道该用哪种方法解决,本文结合一些正则应用的典型应用场景,介绍一下Regex类的基本应用.这里重点进行.NET类的介绍,对于正则的运用,不做深入探讨. 正则的应用最终都是进行模式的匹配,而根据目的的不同,基本上可以分为以下几种应用:验证.提取.替换.分割.结合.NET提供的控件.类以及类的方法,可以很方便的实现这些应用. 以下将结合一些典型的应用场景,对.NET中常见的类.方法及属性进行介绍.本文旨在.NET类基础用法的引导,

正则基础之——贪婪与非贪婪模式

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

原创 正则引擎完工,记录下思路和设计

最近20天都在写这个...终于完工了(走向无尽的重构道路...)...感谢VC聚聚的博文和RE2作者的博客指导,感谢VC聚聚的源码参考.非常感谢!启发很大.vc聚聚的正则语法树遍历部分的方案.真是精妙!之前我虽然知道用Visitor模式遍历异构树,但是不知道怎么写vistor的框架满足需求.用的时候不断地感叹设计的好.不过我也就抄了这块框架代码:)因为实现的太好了.其他都是根据博文给的参考设计自己去想设计和实现 整个引擎实现了http://blog.csdn.net/lxcnn/article/