得,最终博客还是咕了(接近) 5 个月,上次更新是 2018 年 10 月 7 日,再不发点儿什么说不过去了。正好最近的几个 Project 需要做规律处理,用到了正则表达式,于是写一写如何快速入门正则表达式。

首先啥是正则表达式?

总的来说,正则表达式(Regular Expression)是一个表达文本规律的运算符,例如你的系统上的 /dev 目录下上有 sda sdb sdc sdd sde sd.. 这几个驱动器,然后想 ls 列出他们,就可以用正则表达式使 ls 只列出 sd 开头的,而 sd[a-z] 则是这些文字共有的规律。

注意事项

不同的语言、工具可能使用不同的 implementation 实现正则表达式,本文中使用的正则表达式为 GNU Extended Regular Expression,即 grep -E 或 egrep 的实现。本文仅仅包含了一小部分的正则表达式语法供初学者入门,正则表达可以做更多的事情。

一些特殊符号

在正则表达式中,一些符号有特殊的意义,因此在使用这些符号时应使用 \ 来对这些符号进行 escape(即在 \ 符号之后的一个字符为字面意义,不解析为特殊意义)。

这些特殊符号有

符号
意义
^开始
$结束
[]单一字符列表
(用于检查文本中是否存在指定的单一字符)
()分组
?可选匹配(optional match)
+重复匹配
.任意单一字符
*一次或多次匹配符
{}重复匹配次数({0,3} {3,} {,5} 等)
\逃避符(escape)

开始符 ^

符号 ^ 表示一行文本的最启始的位置

表达式匹配匹配
^hehello
hen
helen
headache
computer
they
^ininternet
information
internatioal
saint
cabin
string
^wonwon
wonderful
wont
taekwondo

结束符 $

符号 $ 表示一行文本中最后结束的位置。

表达式匹配匹配
ly$fly
holy
ugly
flyman
polymath
lying
er$better
writer
reader
federal
version
verbose

组合使用 ^ 与 $

组合使用 ^ 与 $ 可实现对一个规律在一个段落中的完全匹配

表达式匹配不匹配
^ly$
lylying
polymath
holy
^he^hehelen
she
chew

单一字符匹配列表 []

通过 [] 符号可以表达需要匹配的字符的列表,在 grep 所使用的 正则表达式中,[] 可包含一个规律如 A-Z (大写字母A-Z),a-z (小写字母 a-z),0-9(数字 0-9),也可以包含单一的字母如:atg。当然规律也可以是不连续的如 E-J(字母 EFGHIJ),也可以是组合的如 A-Za-z0-47-9(所有大小写字母和 01234789)。

表达式匹配不匹配说明
[0-9]aa12345ff
345
3
30123ff
f241
english
hello
wonderful
nothelpful
world
0123456789
[A-Za-z]123world456
heLLo123
456world
123
456
789
abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ
[A-Za-z0-47-9]asdf1234fghj
1234zxCv
zxcv4321
56
6
5565656566655656
abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ01234789
[A-Gvbnm4-609]Access
version
9k
z5
XYZ78
8
888877
3LL
ABCDEFGvbnm45609

上面的例子读者们可能会产生一些疑问:表达式 [0-9] 中,为什么 aa12345ff 也会被匹配到?这是因为此表达式为 [0-9] 而非 ^[0-9]$,因此并不限定 0123456789 在段落中的哪个位置会出现,故此 aa12345ff 中,1 匹配到了 [0-9] 规律,所以被显示出来。当然,如果只希望看到被匹配到的,则可以使用 grep -o,-o 标记则只会显示匹配成功的内容。但是这样获得的结果将会是 1 2 3 4 5,在现实中实际意义可能不大,本文之后会讲到 + ? 和 {} 的使用。

[] 与 ^ 和 $ 的组合

由于正则表达式极为灵活,当然可以继续组合不同的符号以达到不同的效果

表达式不匹配不匹配说明
^[A-E0-4]Center01
234567
Abcdefgh
center
667788
Fake
开头为 A、B、C、D、E、0、1、2、3、4 的段落
[D-G5-7X-Z]$whatever6
112233Z
1230000Y
6whatever
Zcenter
123000
结尾为 D、E、F、G、5、6、7、X、Y、Z 的段落
^[1-37-9]$1
3
8
ca12
356
89asd
包含单一字符 1、2、3、7、8、9 的段落

无限重复匹配符 + 的使用

有些时候需要对一个规则反复在段落中进行匹配,这时可以使用无限重复匹配符 +,+ 代表这个规则匹配到一次或更多。如 [0-9]+ 则会匹配 3 或 356721011024,如果需要提取数字如电话号码等则可以使用这个符号,该符号建议和 ^、$ 等符号组合使用,并且在测试本符号时建议使用 grep -o 来只显示出匹配的内容。

表达式匹配匹配说明
^[0-9]+$13800138000
5
12739123817
Internet114514
cyber123
wolf
匹配只包含 0、1、2、3、4、5、6、7、8、9 且重复一次或以上这些数字的段落
^[A-Za-z]+$Internet
network
iNtErNationAl
K
S
internet123
543network
inter123net
匹配只包含 A-Z、a-z 且重复一次或以上的段落
^[A-Z0-9]+$A3CC5ESS1
EXC456EL
3
ASD
access123
ExCel
匹配只包含大写字母或数字或混合的段落

限定重复次数符 {}

当有些时候只想匹配重复制定次数的规律的时候,则可以使用 {} 来限定重复多少次。如只希望规律重复 11 次时,则可以使用 {11} 来限定。如希望匹配规律重复不大于 5 次,则可以使用 {,5}。如希望规律重复 8 次或以上,则可以使用 {8,}。如希望规律重复 5 – 10 次,则可以使用 {5,10}。

表达式匹配匹配说明
^[0-9]{11}$01239876541
67194815681
123456
1
匹配重复11 次数字的段落
^[E-G]{,4}$EFF
E
EF
GGEE
EEEFF
ABCDE
ABC
EEEEEE
匹配 E、F、G 且只重复 4 次或以下(最低限度为 1 个)的段落
^[a-zA-Z0-9]{5,}$hello
world1news
weLcome2HEre
114514
hi
11
abc
4514
匹配所有数字字母且重复 5 次或以上的段落
^[a-z]{3,7}$admin
root
sysadm
administrator
sa
sysadmin
123456
匹配小写字母 a 到 z 且重复 3 至 7 次的段落

分组符 ()

有些时候需要匹配一些复杂的规则,这时可以用分组符来代表不同匹配的部分。
如在处理 csv 文件时,文件格式如下:
abcdefg,123456
hello,95
center,100049
我们想匹配这两部份,则可以用 ([a-z]+),([0-9]+),这样匹配成功之后就可以用 \1 代替第一部分,\2 代替第二部分,供文字处理使用。
分组符也可以用于多个连续的规则使用,如我想匹配:
HaJcKeUvPo,规则是一个大写字母紧跟着一个小写字母,这时就可以使用 ([A-Z][a-z])+ 来进行匹配

表达式匹配匹配说明
^([A-Z][a-z])+$CeShWeNbEn
SaGeErWaNg
XiAoXiOnGwEiNi
CeshiWenben
weinixiong
SaGeErWang
匹配符合一个大写字母紧跟着一个小写字母的段落
^([A-Z][0-9]){4}$A1B2C3D9a0c9u3j4
A1B2C3D4E5
匹配符合一个大写字母紧跟着一个小写字母且此规则只重复 4 次的段落

或许存在符 ?

有些时候,一个规律可能存在也可能不存在,这时候就需要使用 ? 来代表一个匹配 0 或 1 次。举个栗子:如果想匹配一堆英文字母和一堆英文字母后面一堆数字(也可能没有)的段落,则可以使用 ? 来进行匹配(^[A-Za-z]+([0-9]+)?$)。

表达式匹配匹配说明
^([a-z]+)([0-9]+)?$internet1234
helloworld
internet!@#$
1234inter
包含小写字母重复一次或更多且可能存在数字重复一次或更多的段落
^([A-Z][a-z]([0-9])?)$XiXi1HaHa2
XiXi2HaHa
XiXi1HaHa234包含一个大写字母紧跟着一个小写字母或许紧跟着一个数字的段落

任意单一字符 .

一个点(.)代表匹配任意单一的字符,如:^[A-Z].[a-z]$,则可以匹配:A3x、B!d,但不能匹配A33x、Bd。

或许存在或更多 *

这里的 * 相较于 ?,则可以匹配多次的。举个栗子:^[A-Za-z]+[0-9]?[A-Za-z]+$ 和 ^[A-Za-z]+[0-9]*[A-Za-z]+$ 有什么区别呢?

前者可以匹配 “HelloWorld”、“Hello9World” 但不能匹配 “Hello987World”,而后者则可以匹配 “HelloWorld”、“Hello9World” 和 “Hello987World”。

练习

光看是没用的,需要练习才可以更加深入的理解。

建议使用 https://regexone.com/ 进行练习。

Leave a Reply

Your email address will not be published.

*

code