正则表达式入门

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

基本字符

[] :用于自定义范围集,可指定字符、字符区间、或固定范围集

表达式描述
[abc]任意范围字符集。匹配集合中所含的任意单个字符。
[^abc]排除范围字符集。匹配任何不在集合中的字符。
[a-z]字符范围。匹配指定范围内的任意单个字符。
.匹配除换行符以外的任何单个字符,包括本身。
\转义字符。用于表示特殊字符,如:^ - [ ] $ / 等字符
\w匹配任何字母、数字、下划线中的任意单个字符(等价于[A-Za-z0-9_])。
\W\W 表示\w之外的字符,等价于[^A-Za-z0-9_])。
\d数字。匹配0-9任何数字。
\D非数字。匹配任何非数字字符。
\s空白。匹配任何空白字符,包括空格、制表符、换行。
\S非空白字符。匹配任何非空白字符。

多个字符集可以组合在一起,形成一个更大的字符集,如:[\d\s]

逻辑控制符

​ 在正则表达式中也有逻辑计算符,例如正则 Hi ,表示第一个字符等于H并且第二个字符等于i,它们是默认的&&计算。如果要表达的关系,就在中间加一个| ,如H|i表示等于H等于i。

​ 正则中的逻辑控制符只有以下三组:

逻辑符描述
`` 或
() 子表达示用于独立计算括号中的内容,支持嵌套。如:`(张
{} 数量控制对字符或字表达的数量范围进行限定。如:张.{1,3} 表示“张”后面只能跟1到3个任意字符。

注意:正则中不存在异或( ^ )逻辑

说明| 在类Unix系统中使用问题

由于 | 在类Unix系统中是特殊字符,当你使用grepvim 进行正则搜索时,必须进行转义。在类Unix系统使用正则搜索正确姿势是:

# grep 使用正则
grep '401\|403\|404\|500' nginx.access.log

# 在vim 中输入/ 开始正则搜索,同样|需要转义
/401\|403\|404\|500

子表达式

​ 子表达示支持嵌套,如:(www|mvn|test-(bj|sz|gz|sh)).coderead.cn 表示 test子域名又可继续拆分为test-bj、test-sz、test-sh、test-gz。

​ 子表达示也可用于分组引用

数量控制

量词:即正则表达式中用于范围控制的符号,如 * + ? {m}

​ 数量控制作用于字符子表达示,已限制其数量范围。\d{6}表示必须是6位数字。请注意:一个{}仅作用于其前面的单个字符如:hi{2} 表示hii,而不是hihi

​ 量词 * + ? 实际就是对使用 {} 进行数量控制的一个简写

表达式描述
?匹配前面的表达式0个或1个。即表示可选项。相当于{0,1}
+匹配前面的表达式至少1个。
*匹配前面的表达式0个或多个。
{m}匹配前面的表达式m个。
{m,}匹配前面的表达式最少m个。
{m,n}匹配前面的表达式最少m个,最多n个。

Q:如何限制文本的长度范围?

A:例如限制密码的长度为6~20位:^.{6,20}$

注意? 用于量词后面可以表示最少化匹配的意思(懒惰匹配)

​ 下面举例说明 ? 的使用场景,下文中包括几对<span></span>标签?

<span>hello</span>  <span>uncle</span>

​ 按照一般的思维肯定是两对<span>标签,但是实际上有3对,因为对于整个文本来说还有一对 <span>hello...uncle</span>

​ 如图所示,如果使用正则表达式 <span>.*<span> 匹配<span>标签,那么将会匹配到最大的<span>hello...uncle</span>标签,而不是像预期的那样匹配到两个小的/标签。

image-20220624162025587

​ 这时候就可以在量词后面加 ?,告诉正则表达式引擎按最少化匹配。

<span>.*?</span><span>.*</span> 的区别可以这样理解,两个正则都是以 <span> 开头,中间为任何内容,直到遇到</span>。但.*非常“勤奋”,就算遇到了一个</span>,还会继续向后查看是否还有,后面又找到了一个,就以最后找到的为准。而.*?就比较“懒惰”,遇到第一个</span>就直接匹配为一对<span>标签,然后就去查找下一对 <span> 标签了。

分组、引用和替换

表达式描述
(expression)分组。匹配括号里的整个表达式。
(?:expression)非捕获分组。匹配括号里的整个字符串但不获取匹配结果,拿不到分组引用。
\num对前面所匹配分组的引用。比如(\d)\1可以匹配两个相同的数字,(Code)(Sheep)\1\2则可以匹配CodeSheepCodeSheep
$组号替换。替换操作指将正则匹配到的内容,替换成指定字符串,该字符串可通过$组号引用组进行拼装。通过$0可以引用整个匹配的内容。($0在 Python与Javascript中不支持,使用$&代替)

说明

  • [] 和 () 的一个需要注意的区别是 [] 只能匹配单个字符,而 () 可以匹配多个字符。
[abc] 匹配 a 和 b 和 c
(abc) 匹配 abc

分组

分组指将匹配的内容,使用( )划分成多个组块,分好的组可用于提取、反向引用以及替换操作。

image-20220624165354986

举例1:在 javascript 中使用分组

// javascript
"小丽生日是2011-11-23".match(/(\d{4})-(\d{2})-(\d{2})/);
// 得出结果如下:
['2011-11-23', '2011', '11', '23']
// 一对括号表示一个分组,从1开始计数
移除分组

()即用于子表达示,同时也是一个分组。如果只想用作子表达示,而不想用于分组就可以使用(?: )从分组列表中移除。比如(?:\d{4})-(\d{2})-(\d{2}) 该表达示只存在两个组,月$1和日$2

嵌套分组

在嵌套分组中组号是如何命名的呢?比如:生日((\d{4})-(\d{2})(\d{2})) 其组号的命名顺序是以开括号出现顺序为准。

image-20220624180531110
分组+量词

​ 同一个分组如果使用了量词,该分组会代表多个值,这时通过$组号去提取值的时候会得到该组最后匹配的值。如 (\d)+ 匹配12345,通过 $1 将得到 5

反向引用

反向引用:指在表达示中通过\组号引用之前的分组,但是不能够引用之后的内容。

image-20220624170936130

举例2:在正则中引用分组,匹配html中的所有标题内容

​ 文本内容如下

<h1>一级标题</h1>
<h2>二级标题</h2>

​ 如果不使用分组,可以按照如下方式匹配,但是这样非常繁琐。

<h1>.*?<\/h1>|<h2>.*?<\/h2>

​ 通过反向引用可以简化正则表达式

<(h[1-2])>.*?<\/\1>
image-20220624170936130

引用替换

引用替换:正则有着强大的替换能力,比如匹配文本中所有空行,然后替换为空(删除);或者匹配所有的注释,然后替换为空;或者匹配普通文本中的所有http链接,然后替换为<a>标签;或者将文本替换为 insert sql 语句。 image-20220624172529129

举例3:将下文中所有日期替换成yyyy-MM-dd 格式

​ 实现替换的步骤如下:

  1. 写出匹配日期的正则:\d{4}[-.\/]\d{2}[-.\/]\d{2}
  2. 对日期年、月、日进行分组:(\d{4})[-.\/](\d{2})[-.\/](\d{2})
  3. 在替换字符中引用分组:$1-$2-$3
image-20220624172529129

​ 替换后的结果

image-20220624172805480

大小写转化

​ 在Idea、VS Code、Sublime、Notepad++等工具进行替换操作时,还可以使用下表中操作符进行大小写转换,但是在编程语言中是不支持的。

操作符描述
\u 单个转大写转换下一个字符为
\U 全部转大写转换\U后所有字符转
\U…\E 区间转大写\U\E区间的内容转
\l 单个转小写转换一下个字符为小写
\L 全部转小写转换\L后所有字符转小写
\L…\E 区间转小写\L\U区间的内容转小写

具体使用方法是:在替换字符串中加入转换操作符。

举例:把单词首字母转成大写

  1. 编写匹配正则:\w+
  2. 首字母转大写并替换:\u$0
image-20220624174203536

​ 转换后的结果为:Hello World!

边界断言

边界断言:指一段表达示前后是否满足指定条件,该条件由一个子表达式组成,基于前后字符能否匹配来计算布尔值。因断言部分不会消耗匹配字符,固又称为零宽断言

边界断言让正则有了条件判断的能力,功能更加强大。

特殊边界断言

表达式描述
^匹配断言文本或行开头。
$匹配断言文本或行结尾。
\b匹配断言单词的开头或结尾。比如Sheep\b可以匹配CodeSheep末尾的Sheep,不能匹配CodeSheepCode中的Sheep
\B匹配非单词边界或结尾。比如Code\B可以匹配HelloCodeSheep中的Code,不能匹配HelloCode中的Code
\A 文本开头断言文本开头。JavaScript 不支持
\Z 文本结尾断言文本结尾。JavaScript 不支持

说明

  • ^$ 配合边界/m使用表示每一行的开头和结尾,否则表示的是整个文本的开头和结尾。被m修饰后,^表示行的开头,等价于(?<=\n|\A),被m修饰后,$表示行的结尾,等价于(?=\n|\Z)
  • \b 单词边界本质上还是一个边界断言,符合边界断言的特性。\b断言单词的前后是一个\W字符,或是一个其它边界(行边界,文本边界)
\bhello\b 等价于 (?<=^|\W|\A)Hello(?=$|\W|\Z)

边界断言语法

表达式描述
(?=)前置断言,判定一段表达式前面是否满足条件。比如Code(?=Sheep)能匹配CodeSheep中的Code,但不能匹配CodePig中的Code
(?!)前置否定断言,判定一段表达式前面是否不满足条件。比如Code(?!Sheep)不能匹配CodeSheep中的Code,但能匹配CodePig中的Code
(?<=)后置断言,判定一段表达式后面是否满足条件。比如(?<=Code)Sheep能匹配CodeSheep中的Sheep,但不能匹配ReadSheep中的Sheep
(?<!)后置否定断言,判定一段表达示后面是否不满足条件。比如(?<!Code)Sheep不能匹配CodeSheep中的Sheep,但能匹配ReadSheep中的Sheep

说明:所谓前置后置是以表达式为中心,边界断言位于表达式的前面(左边)和后面(右边)

例如:(?<=身高)\d{3}(?=cm)(?<=身高)为后置断言(表达式后面),(?=cm)为前置断言。

注意:后置断言在javascript中只有部分浏览器支持。另外后置断言非常消耗性能,所以不推荐使用无限大的量词如:* + {n,}。甚至在JAVA、Python、PHP会直接报语法错误

高级特性

  1. 零宽断言:断言条件本身不会消耗字符
  2. **多边界断言:**一个正则可同时存在多个边界断言。根据其所处位置来决定断言的边界。
  3. 条件组合:多个子断言可以进行布尔运算如:&& || ()
  4. 任意边界:可以是任意合法的表达式边界,甚至可以是字符边界。

高级特性之条件组合

边界条件本质上就是布尔值计算,其自然可以进行类似&& || ()布尔运算,以应对更复杂的场景。其书写方式有以几种:

  1. h(?=条件1)(?=条件2) 运算,指必须同时满足多个条件
  2. h(?=(?=条件1)(?=条件2)) 运算,条件1与条件2组成一个新条件,并且两个条件都必须满足
  3. h(?=(?=条件1)|(?!条件2)) 运算,满足条件1或者 不满足 条件2
  4. h(?=表达式1|(?=条件1)(?!条件2)) 混合运算,表示满足表达式1或者同时满足条件1、2

上述条件组合在后置断言中同样适用,而且没有额外的兼容性问题。另外上述任意条件都是基于同一个边界进行计算,即字符h

修饰符

修饰符用于影响表达式的匹配逻辑。

表达式描述
/.../i忽略大小写。(… 表示正则表达式)
/.../g全局匹配。默认只会匹配一个结果,加上 g 后会匹配全部可匹配结果
/.../m行边界修饰符。用于多行匹配。
/.../s使用此修饰符后 . 能匹配任意字符,包括换行符。
/.../x书写正则表达式时会忽略空白字符,可以多行书写,并可以使用#进行注释说明。JavaScript 不支持

/m 的理解:它的作用是于定义^$边界断言的作用范围。默认情况下^$分别表示文本的开头与结尾,加上之后表示行首行尾,也包括文本开头与结尾。一般的正则表达式应用都会加上m修饰符。

​ 在使用类似idea,vs code,或notepad++等工具时,其正则都添加了gmi三个修饰符,而且除了i大小写勿略,其它都不可以改变。

常用正则表达式示例

详情参考

参考资料

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值