威力无比的正则表达式

前言

正则表表达式作为一种强大文本处理工具,可以用于执行各种复杂的文本处理和操作,并且在不同平台,不同语言都有支持。那么怎么才能用好它呢

为什么要克制使用?

正则表达式功能强大,处理速度快,但是天书符咒般的写法,从软件工程的角度看来,大大降低了程序的可读性可维护性

能用普通字符串处理的,坚决用普通字符串处理

字符串处理速度不见得比正则差,但可读性却好很多

使用正则正确姿势

每一个正则都需要注释

你看得懂,你的同事不一定看得懂;你现在看得懂,过一阵子,不一定还能看懂。

多个简单正则表达式代替一个复杂正则表达式

通过拆分,分别对多个验证条件进行验证

正则能做什么

正则的结构

模式

贪婪模式

表示次数的量词,默认是贪婪的,默认尽可能多的去匹配,会发生向后回溯(回吐)

非贪婪模式

“数量”元字符后面加?,找出长度最小且满足要求的,会发生向前回溯

独占模式

尽可能多去匹配,匹配失败就结束,不会回溯;

独占模式,但是某些场景会不满足需求;而且不同语言支持度也不一样

分组与引用

正则在处理多分支匹配时,都是左边的优先匹配

括号在正则中可以用于分组,表示一个子表达式的子组。

通过将某部分看成一个整体,在后续查找和替换中引用分组

匹配模式

不区分大小写模式(?i)

修饰符在括号内还是括号外具有不同的意义

点号通配模式(?s)

把文本当成单行进行匹配,也叫作 单行匹配,可以匹配任意字符,包括换行

多行模式(?m)

进行多行匹配,通过^和&匹配上每行的开头和末尾

注释模式(?#comment)

使正则更容易阅读

正则断言

在我们进行正则匹配的过程中,有些情况下,我们需要对匹配的文本的位置有一定的要求。 正则提供断言的方式用于匹配位置。

单词边界

\b:理解为边界(Boundary),正则中可以表示为单词的边界

行的开始/结束

使用^和$进行位置界定每行的开始和结束,匹配要求的内容以行首或行尾出现。比如日志起始行判断,输入数据校验

环视

环视要求匹配部分前面或后面要满足某种规则,零宽断言

 ?<=Y肯定逆序环视左边是Y
 ?<!Y否定逆序环视左边不是Y
 ?=Y肯定顺序环视右边是Y
 ?!=Y否定顺序环视右边不是Y

子组的作用是匹配文本内容,后续用于替换等操作;环视是对文本左右环境的要求,只匹配位置,不匹配文本内容

转义字符

字符序列中的转义字符对其后续几个字符进行替代并解释

通常用法

常见转义字符

正则转义

正则中使用反斜杠进行转义

如果要在文本中查找转义的反斜杠,则需要4个\

正则中方括号[]和花括号{}只需转义开括号,但圆括号()两个都要转义

转义函数

不同编程语言自带转义函数进行转义

Python:re.escape(text)
Go:regexp.QuoteMeta(text)
Java:Pattern.quote(text)
PHP:preg_quote(text)

字符组转义的情况

脱字符在中括号中,且在第一个位置

[^ab]  表示非

[\^ab] 表示独立字符^

中划线在中括号中,且不在首尾位置

[a-c] 表示a到c中任意字符
[a\-c] 表示独立字符 a,\,c

右括号在中括号中,且不在首位

[a]b] 匹配ab]
[a\]b] 匹配 a]b

字符组中其他元字符(.*+?())在中括号中不需要转义即可表达单个字符本身的含义。

[.*+?()]  表示独立字符 .*+?()

正则表达式的流派

POSIX字符组

PCRE流派中直接兼容的有Perl,PHP,preg等语言库;间接兼容的有Java系,Python,JS,.NET等语言

有些不同的工具同时兼容两种标准,例如:

grep -E 使用ERE标准

grep -P 使用PCRE标准

我们常用的语言中字符串正则处理,查找匹配,提取内容,替换,分割等操作,Java由于没有原生字符串所以在使用转义字符\时需要对其转义\

字符编码的正则匹配

Unicode对世界上大部分文字进行整理,编码。使得计算机呈现,处理文字变得简单。

现Unicode字符分为17组编排,每组一个平面,每个平面65536个码值

在正则匹配过程中,如果不使用Unicode,正则会被编译成其他编码表示形式,每个编码形式最终使得正则匹配可能通过单字符进行匹配,导致匹配异常

点号在不同语言中对Nnicode字符匹配的支持不一样,同样字符组也是

Unicode的属性可以把Unicode字符集划分成不同的字符小集合

正则匹配原理

有穷状态自动机

一个系统具有有穷个状态,不同状态代表不同意义;系统根据相应条件,不同状态下进行转移。

回溯

只有在NFA引擎才有,且正则中出现量词,多选分支结构时,才会发生回溯

贪婪模式下,可能会导致大量回溯,造成匹配内容不断吐出,再次尝试的过程

POSIX NFA相比传统NFA会在找到可能最长匹配之前会继续回溯,找到最长匹配

正则优化

测试性能

通过耗时和文本匹配次数(regex101.com)来得知正则性能信息

正则处理思路