正则表达式从入门到出门

01

引言

在程序员的日常工作中,似乎人人都会碰到正则表达式。诸如:校验密码强度、身份证号、邮箱格式等用法,它的功能如此强大,几乎可以完成任何搜索与匹配的功能。同时,它又如此繁琐与庞杂,让人望而却步,从未想过真正掌握与了解。需要使用时,常见做法是在搜索引擎苦苦求索。诚然,一些常用场景已有成熟的解决方案可供使用,然而,针对高度定制化需要自行构造正则的应用场景,无不抓耳挠腮痛苦万分。本文通过简单介绍正则表达式的基本语法及应用示例,希望在正则的使用上能带来一些帮助。

正则表达式从入门到出门
正则表达式从入门到出门

02

简介

正则表达式从入门到出门

正则表达式(regular expression,简称regex)起源于上世纪90年代在数学领域的一些研究工作,计算机领域在借鉴这些研究成果与思路之后,开发出了Unix平台中的Perl语言和grep等工具。在之后相当长的一段时间里,正则表达式仅用于Unix平台。而现在,几乎所有的平台都支持正则表达式。

那么,什么是正则表达式。简单来说,正则表达式是用来匹配和处理文本的字符串,有自己的特殊语法与指令。但是正则表达式并不是一种完备的程序语言,甚至算不上是一种能够直接安装并运行的程序。准确来说,正则表达式更像是内置于其他编程语言或软件产品中的“迷你”语言。

在如今常用的高级编程语言中,清一色都支持regex。只不过在具体的表达形式上略有差异。比如在java中,由于转义字符的原因,在遇到’\\’时需要使用’\\\\’进行转义,例如:常见的\\d需要写成\\\\d。在js中,则可以直接写成’\\d’。

正则表达式从入门到出门

03

基础规则

正则表达式从入门到出门

纯文本类

Regex: Everbright

Text: Everbright Technology CO.LTD

Everbright是一个正则表达式,可能很反直觉,但它确实是。正则表达式可以包含纯文本内容,甚至可以只是纯文本。它可以匹配到Everbright Technology CO.LTD中的Everbright。

再来看一个纯文本的正则表达式例子:

Ebchinatech

https://www.ebchinatech.com/ebchinatech/622504/index.html

正则表达式是大小写敏感的,因此上边例子中的Ebchinatech是匹配不到ebchinatech的。

特殊字符类

在正则表达式中,特殊字符有特定的含义与用法。

 特殊字符.

“.”可以匹配除了换行符之外的任意一个字符

c.t

cat   cot   c1t   c_t   cert

“.”字符也可以一次使用多个,例如“..”可以连续匹配两个任意字符

c..t

cert   count

“.”也可以出现在表达式的任意位置

.a.

nas   IaaS   Paas

如果需要匹配的文本中,本身带有“.”

 

例如:test.txt  example.xls 这时就需要对.进行转义处理,在表达式中加上一个“\\”

例如:.a..\\.xls  就可匹配到.xls

IaaS.xls   paas.xls   aaaa.txt

 特殊字符*

“*”在正则表达式中指的紧挨着“*”的子表达式的可出现的次数>=0

go* 意味着“*”之前的字母o出现次数>=0

g   god   good   goooood

也可以把“.”“*”组合起来使用

g.* 表示可匹配字母g后跟随任意字符(除换行符外)>=0次

g   god  g123d   gb2312

 特殊字符+

“+”在使用上与*有类似的地方,指的是紧挨着+的子表达式可出现的次数>=1

go+

g    god    good    goooood

 特殊字符?

“?”号表示子表达式可出现的次数为0或1次,也称作可选量词

colou?r  意味着?之前的u,可以出现也可以不出现,所以两个单词皆可匹配

color   colour

 特殊字符()

“()”可以简单理解成对表达式进行分组,通常和其他表达式组合使用

do(es)?  把括号中的es作为一个整体,通过与后边的“?”组合,表示es可有可无,故可以匹配如下结果。

do   does

(ha)+  同理,还有这个+号的例子

haha   hahaha   hah

 特殊字符|

“|”可以理解成条件判断中的或,只选择其中的一个

(c|r)at  表示匹配以c或r字母开头的字符

fat    cat   rat

 特殊字符[]

“[]”用来定义一个字符集,有多种使用方式和表达形式

①  [ABC] 可以匹配[…]中的任意一个字符

a[ABC]c

aAc    aBc    aCc    aABc

② [^ABC]  ^表示匹配除了[…]中的任意字符,相当于对[…]取非

a[^ABC]c

abc      aABCc    aABc

③ [A-Z] 表示的是一个包含两个端点的范围,即匹配从A-Z的任何一个字符,相似的还有[0-9],[a-z]。

[A-Z]

Abc      Bcd

 特殊字符{}

“{}”用来表示重复的次数,有三种写法

①  {x,y} 表示匹配{}前面子表达式x-y次

go{1,2}d 表示匹配o出现1到2次的字符

god    good     goood

②  {x,} 表示匹配{}前面子表达式x到+次

fo{2,}d  因此,这个表达式可以匹配到fooood,但匹配不到fod

food   fod    fooood

③ {x} 这种写法明确了匹配的次数,即只匹配子表达式x次

fo{2}d

food      fod

 特殊字符^

“^”字符单独出现时,限定了匹配字符串的开始位置,通过下边的例子可以很好理解

^talk ([a-z]+ ?)*    “^”表示限定了开始的单词只能是talk,()作为一个整体,()后边的*表示()里的内容出现的次数>=0次。()中使用了字符集[a-z]匹配英文字母,后边的+表示字母可以出现>=1次。后边跟上一个空格和一个?表示空格可以出现也可以不出现。所以,这段正则就可以匹配到如下的内容:

talk is cheap

it is well known that talk is cheap

如果去掉开头的“^”,则可以得到下边的结果

talk ([a-z]+ ?)*

talk is cheap

it is well known that talk is cheap

 特殊字符$

“$”字符的含义与^正好相反,用来标识字符串的结尾。需要注意的是“$”出现在结尾字符的后边

([a-z]+ ?)*code$  第二个字符串没有以code结尾,所以匹配不到

talk is cheap show me the code

talk is cheap

正则表达式从入门到出门

04

特定字符类型

正则表达式从入门到出门

对于一些特定的字符类别,例如:纯数字、空白字符等,为了方便使用会将这类常用的表达式,进行简写定义。

 匹配数字

上边的介绍中已经谈到了匹配数字的方式,比如:

[0-9]可以匹配到0到9的任意一个数字,\\d就是对其的一种简写定义,等价于[0-9],可以匹配任何一个数字

[^0-9]匹配的是非数字的表达式,\\D与之等价。

可以看到\\d与\\D的含义正好相反。

接下来还会看到更多类似的定义,相同之处在于,通过大小写字母的区分,进行取反。

 匹配数字与字母

\\w可以用来匹配数字加字母以及下划线,即\\w等价于[a-zA-Z0-9_]

相反\\W则表示任何一个非数字、字母或下划线字符,等价于[^a-zA-Z0-9_]

 匹配空白字符

空白字符指的是换行、制表位等特殊的字符,如\\n \\t \\r等,

在正则表达式中,使用\\s来匹配所有的空白字符

\\s等价于[\\f\\n\\r\\t\\v]

同理\\S等价于[^\\f\\n\\r\\t\\v]

正则表达式从入门到出门

05

正则表达式实战

正则表达式从入门到出门

前边简单介绍了正则表达式的常见语法与用法,接下来用实际案例,一起感受下正则表达式在真实环境中的应用。需要注意的一点是,对于相同的文本内容,可能会有多个不同的正则表达式,区别在匹配的精确度不同。一般来说,越简洁的表达式可读性越好,越长的表达式精确度越高。

匹配ipv4地址

ipv4地址在日常工作中特别常见,我们的案例就以它展开。

ipv4地址的地址范围是从0.0.0.0-255.255.255.255,为了便于管理,还对其进行了不同的分类。本则案例中,不考虑地址的分类及实际使用情况,仅通过正则表达式将这些地址匹配区分出来。

通过搜索引擎查询,大概会得到这样一个正则:

\\d+\\.\\d+\\.\\d+\\.\\d+

通过分析可以发现,这个流传甚广的正则是错误的。

表达式\\d等价于[0-9],也就是0-9中的任意一个数字,\\d+表示数字的位数>=1直至无穷。显然这并不符合ipv4地址的范围。例如该表达式可以匹配上一个随机滚键盘出来的地址:

367345.543.123.457

介于此,我们尝试重写这段正则。

首先,只考虑组成ip的十进制数字,会发现它是一个0-255的自然数,位数最少为1位,最多为3位。

①当只有个位数字时,可以取到0-9任意一个数,因此:

可以得出表达式\\d

②当有两位数字时,十位不为0,个位可取到0-9中的任意一个数,因此在上述表达式的基础上可以得到:

[1-9]\\d

考虑将个位数和十位数的情况进行合并,加上?即可表示同时表示十位数与个位数

[1-9]?\\d

③当有三位数时,需要考虑多种情况。百位的数字只能取1-2,当百位数字为1时,十位、个位数字可取0-9中任意一个,无限制。当百位数字为2时,十位数字只能取0-5并且且当十位数字为5时,个位数字只能取0-5。

使用正则表达式翻译上述规则,则有:

百位数为1时:

1\\d{2}

百位数为2,十位数为5时:

25[0-5]

百位数为2,十位数不为5时:

2[0-4]\\d

上述各种情况,均可能出现,即逻辑关系‘或’,所以用|连接得到最终的正则表达式:

(25[0-5])|(2[0-4]\\d)|(1\\d{2})|([1-9]?\\d)

使用上述表达式可以正确匹配到组成ipv4地址的数字,一个ip地址由四组数字与三个分割符.组成。分隔符作为正则表达式中的关键字,需要进行转义。最终的正则表达式如下:

((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)

正则表达式从入门到出门
正则表达式从入门到出门

最后留下一个课后作业

尝试编写一条正则表达式,

能同时匹配下边的三条字符串

define service add name TCP46101-46104 protocol 6 ports \'46101-46104 \'define service add name TCP8000-8008 protocol 6 ports \'8000-8008 \' comment \' \'define service add name TCP443 protocol 6 ports \'443 \' comment \'https\'
正则表达式从入门到出门

正则表达式从入门到出门

参考资料:

《正则表达式必知必会》[美] Ben Forta 著 杨涛 等译

https://regexlearn.com/zh-cn/cheatsheet

https://www.runoob.com/regexp/regexp-syntax.html

文章作者:栗   石

排版设计:王蔚棋

手绘插画:岳   媛

在看不好意思,那就点个赞吧

原创文章,作者:EBCloud,如若转载,请注明出处:https://www.sudun.com/ask/33066.html

Like (0)
EBCloud的头像EBCloud
Previous 2024年4月2日 下午3:28
Next 2024年4月2日 下午3:28

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注