正则表达式漫谈

正则表达式漫谈

一个引子:

请教一个正则表达式怎么写,
只能是 a-z、A-Z、0-9、_、-.
其中_ - . 不能出现在首尾
.最多只能出现一次

这是今天群里的一个老哥提的一个需求,白天的时候没写好,晚上的时候再请教了些大佬的意见,列出下面的三种实现方式

方式1

^[A-Za-z0-9]{1}[A-Za-z0-9_-]*?\\.?[A-Za-z0-9_-]*?[A-Za-z0-9]{1}$

这个做法大体是将首尾先固定:

  • ^[A-Za-z0-9]{1}开头位置出现的字符只能是a-z、A-Z、0-9不能是_、-、. 其中^表示以什么字符开头
  • [A-Za-z0-9]{1}$结尾固定,$表示字符结尾标志
  • *表示一次或多次匹配前面的字符或子表达式
  • ?表示零次或一次匹配前面的字符或子表达式
  • 比较难处理的是.这个字符,至多一次,用\\.? 或者\\.{0,1}
  • 注意字符的转义

方式2

^(?![^.]*?\\.[^.]*?\\.)[a-zA-Z][a-zA-Z\\d_\\.-]*?(?<!(\\.|-|_))

  • ^(?![^.]*?\\.[^.]*?\\.) 是从开头的 出现大于等于2个.的情形排除掉,其中
否定型顺序环视 (?![^.]*?\.[^.]*?\.)
?!是断言此位置的后面不能匹配该表达式
匹配不在下列列表中的一个单字符 [^.]*?
*? 量词 — 匹配零个到无穷次,尽可能少匹配,如果有必要,回溯匹配更多内容(懒惰模式)
  • ?<!(\\.|-|_) 为后向后发,断言此位置的前面不能匹配该表达式

  • [a-zA-Z\\d_\\.-]*? 表需要的字符 *? 量词 匹配零个无穷次,尽可能少匹配,如果有必要,回溯匹配更多内容(懒惰模式) \d表示数字

方法3

^(?![\._-])[a-zA-Z0-9_-]*\.?[a-zA-Z0-9_-]*?(?<![\._-])$

  • 此方法是也是我心目中的认为很好的写法,需要拆三段,来处理.多过2次的情况
  • ``^(?![._-])`拿掉开头不匹配的几种情况
否定型顺序环视 (?![\._-])
断言表达式后面不匹配以下正则
匹配下列列表中的一个单字符 [\._-]
\. 按字面匹配 字符 .(区分大小写)
_- 从列表 _- (区分大小写) 中匹配一个单字符
  • (?<![\._-])$拿掉结尾不匹配的几种情况
否定型逆序环视 (?<![\._-])
断言表达式前面不匹配以下正则
匹配下列列表中的一个单字符 [\._-]
\. 按字面匹配 字符 .(区分大小写)
_- 从列表 _- (区分大小写) 中匹配一个单字符
  • \.? 是处理包含. 0 次或者1次的情况
? 量词 — 匹配零个到1次,尽可能多匹配,如果有必要,回溯匹配更少内容(贪婪)
  • *?量词 — 匹配零个无穷次,尽可能少匹配,如果有必要,回溯匹配更多内容(懒惰模式)

测试效果

在这里插入图片描述

  • 下面的正则是组内分享过的PPT,拿来润色了下

预热

在这里插入图片描述

分组

组是用括号划分的正则表达式,可以根据组的编号来引用某个组。组号为 0 表示整个表达式,组号 1 表示第一对括号扩起的组,以此类推。

1. ((A)(B(C)))
2. (A)
3. (B(C))
4. (C)

再比如 A(B©)D 有三个组:组 0 是 ABCD,组 1 是 BC,组 2 是 C,
可以根据有多少个左括号来来确定有多少个分组,括号里的表达式都称子表达式。

在这里插入图片描述

/***********************/
(\d{4})-(\d{2}-(\d{2}))
2021-03-05
/***********************/

零宽断言

SubjectDetail
(?=exp)断言自身出现的位置后面能匹配表达式exp
(?<=exp)断言自身出现的位置前面能匹配表达式exp
(?!exp)断言此位置的后面不能匹配表达式exp
(?<!exp)断言此位置的前面不能匹配表达式exp

在这里插入图片描述

情况1:(?=exp)

  • 零宽度正预测先行断言 表示匹配表达式前面的位置

在这里插入图片描述

先行断言的执行步骤是这样的先从要匹配的字符串中的最右端找到第一个 ing (也就是先行断言中的表达式)然后 再匹配其前面的表达式,若无法匹配则继续查找第二个 ing 再匹配第二个 ing 前面的字符串,若能匹配则匹配,符合正则的贪婪性

在这里插入图片描述

/***********************/
(?<=<div>).*(?=</div>)
<div>www.github.com</div>
<div>www.baidu.com</div>
<div>www.google.com</div>
/***********************/

情况2:(?<=exp)

  • 零宽度正回顾后发断言 表示匹配表达式后面的位置

(?<=abc).* 可以匹配 abcdefg 中的 defg

后发断言跟先行断言恰恰相反 它的执行步骤是这样的:先从要匹配的字符串中的最左端找到第一个abc(也就是先行断言中的表达式)然后 再匹配其后面的表达式,若无法匹配则继续查找第二个 abc 再匹配第二个 abc 后面的字符串,若能匹配则匹配

在这里插入图片描述

/***********************/
(?<=anti-).*
anti-knock
anti-foreign
anti-war
anti-recall
/***********************/

在这里插入图片描述

/***********************/
(?<=cookie:).*
accept: text/plain, */*; q=0.01
accept-encoding: gzip, deflate, br
accept-language: zh-CN,zh;q=0.9
cookie: _ga=GA1.2.534134663.1589797467; Hm_lvt_a
/***********************/

在这里插入图片描述

/***********************/
(?<=src=\").*?(?=\")
<img src="/UploadFiles/image/20140304/20140304094318_2971.png" alt="" />
/***********************/

在这里插入图片描述

/***********************/
(?<=url\()[^\)]+
local('OpenSans-Light'),url(http://www.github.com) format('woff2');
/***********************/

情况3:(?!exp)

  • 负向零宽先行断言

在这里插入图片描述

/***********************/
(?!.*\.min\.css$)\w+\.css
a.min.css
b.css
min.css
.min.css
/***********************/

情况4:(?<!exp)

  • 匹配前面不是小写字母的11位数字

在这里插入图片描述

/***********************/
(?<![a-z])\d{11}
abcdef
13011223344
130112A23344
a13011223344
a13011223344
/***********************/

贪婪/懒惰/独占

Greedy:贪婪
  匹配最长。在贪婪量词模式下,正则表达式会尽可能长地去匹配符合规则的字符串,且会回溯。

Reluctant :非贪婪
  匹配最短。在非贪婪量词模式下,正则表达式会匹配尽可能短的字符串。

Possessive :独占
  同贪婪一样匹配最长。不过在独占量词模式下,正则表达式尽可能长地去匹配字符串,一旦匹配不成功就会结束匹配而不会回溯。

在这里插入图片描述

  • 贪婪模式即在X字符后面增加限定符号如:?、*、+、{n}、{n,}、{n,m}
  • 懒惰模式是在带有限定符号:?、*、+、{n}、{n,}、{n,m}的后面,增加”?”,如:X??
  • 独占模式也叫侵占模式,是在带有限定符号:?、*、+、{n}、{n,}、{n,m}的后面,增加”+”,如:X?+

Greedy:贪婪

在这里插入图片描述

首先 .* 匹配任何字符(在非 DOTALL 模式下不匹配 \n,\r,\a 一类字符),在 source 中第一个被匹配的

  • 后面直至最后一个字符(也就是的 >)都符合 .* 的匹配规则,但是显然如果 .* 匹配到最后一个字符,那么没有剩余的字符去匹配正则表达式中还未匹配的
  • 的,那么会引起 匹配失败。但是 失败后会回溯(这一点与独占量词不同,下面会讲到)。回溯后这段正则表达式将匹配到 source 中第一个
  • 和第二个
  • 以及之间的内容,如上面的输出所示。

Reluctant :非贪婪

在这里插入图片描述

source 中第一个

  • 匹配到之后到第一个
  • 之间的字符都符合 .* 的匹配规则,同时如果继续匹配 也符合这个规则,但是勉强模式下,它会尽可能短地匹配字符串,故第一个找到的字符串应该是
  • Ggicci’s Blog
  • ,如上面输出所示。然后它会继续匹配剩余的字符串,找到第二个。

Possessive :独占

在这里插入图片描述

这段正则表达式将不会在 source 找到任何匹配的内容,因为

  • 匹配到后, .*+ 所能匹配的字符尽可能长地匹配下去,直到 source 的最后一个字符,这必将引起匹配失败,但是在独占模式下一旦匹配失败就不会回溯,故不存在像贪婪模式一样回溯之后找到 之前的
  • 的情况。

/***********************/
//贪婪
(?<=<h3>).*(?=</h3>)
<h3>abd</h3><h3>bcd</h3>
(?<=<h3>).*?(?=</h3>)
//懒惰
/***********************/

在这里插入图片描述

20210304181319727

正则表达式的匹配模式
-IGNORECASE 忽略大小写模式:默认情况下正则表达式区分大小写
-SINGLELINE单行模式:整个文本看作一个字符串,只有一个开头,一个结尾。使.可以匹配包含换行符在内的任意字符
-MULTILINE 多行模式:每行都是一个字符串,都有开头和结尾。\A -->开始字符,\Z–>结束字符

实战场景

  • IDEA中查找接口

在这里插入图片描述

  • 搜索系统的文件

在这里插入图片描述

  • 替换文本中的指定字符

在这里插入图片描述

  • markdown格式的文本中,高亮英文字符

在这里插入图片描述

推荐几个正则的工具/网站

  • 嗨正则 : 在线正则,有注释,方便理解正则每一段的含义,可以生产代码

在这里插入图片描述

  • RegexBuddy:客户端,功能强大,也是我常用的一个正则处理工具,支持多种语言,高亮,分组等,支持debug,test模式

在这里插入图片描述

  • debuggex: 支持正则可视化的在线正则网站,需要梯子

在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值