正则表达式语法

正则表达式语法

从下面开始,将逐步讲解正则表达式的语法

匹配普通文本

普通匹配文本直接输入文本内容即可

文本信息

例如我们匹配python

/python

结果如下:

在这里插入图片描述

注意,我们直接进行纯文本匹配的话,就会匹配出来所有的python内容,即便python这个字符串是包含在另一个单词中

例如这里的pythonbrewpythonz以及第33行的带有python的连接

此外,正则表达式是不区分大小写的,所以python也会匹配到Python

实际上我们只想要单纯的python单词,并不想要python作为其他字符串的子串,在后续的学习中,我们将逐渐学习如何只匹配我们需要的内容


匹配一个任意字符

在正则表达式中.是一个特殊符号,我们成为元字符,元字符.可以用来匹配任意的一个字符

例如c.t可以匹配到cat,cot,c t,c5t

例如匹配如下内容

/py.

在这里插入图片描述

可以看到,匹配的结果不仅有pyt,还有pye

我们也可以在一个正则表达式中多次使用.

此外,我们如果直接在一个正则表达式中使用.,那么将会被视为通配符,而非普通文本.,如果我们想要匹配.本身的话,我们可以使用转义符号\来使.失去作用,从而作为纯文本被匹配

实际上\可以使任何的元字符失去作用成为一个纯文本来匹配,例如

/..\.

在这里插入图片描述

\本身也是一个元字符,我们也可以转义\本身来匹配\,例如

/...\\..

在这里插入图片描述


匹配指定字符集和中的一个字符

前面使用.能够匹配一个任意的字符,但是有的时候我们却希望匹配一个在指定范围的字符

例如我们只想在匹配一个数字,而非任意的字符,因为任意的字符将会匹配到符号,字母等等

我们可以使用元字符[ ]来匹配一个指定字符集合中的一个,两个中括号见间的内容将作为匹配项,并且其中的部分元字符会被当做普通文本处理

例如匹配

/..[0123456789]..

在这里插入图片描述

注意[0123456789]只会匹配一个数字

实际上我们可以使用-连字符来连接两个字符,这样将会匹配的范围为前后两个字符的ASCII码中的所有字符

而且在一对[]内可以多次使用简写形式以及与单个字符混合使用,例如

/..[0-9.][a-z+_0-9]\.

在这里插入图片描述


匹配非指定字符集和中的一个字符

实际上我们除了指定匹配的字符集合,我们也可以进行反向匹配,即匹配不是指定字符集合中的一个字符

例如匹配除了数字和字母以外的所有字符

我们可以将元字符[^ ]来指定不匹配的字符集合,例如

/[^0-9a-bA-B]

在这里插入图片描述


匹配空白字符

元字符大致可以分为两种:

  1. 用于匹配文本的,例如.
  2. 作为正则表达式的一部分,如[ ],[^ ]

空白字符由于不能像普通字母一样来打印出来(虽然具有视觉效果),所以我们使用特元字符来表示空白,并且匹配的时候不会类似于匹配其他文本一样会有高亮显示

常见的换页符如下:

元字符说明
\f换页符
\n换行符
\r回车符
\t制表符(Tab键)
\v垂直制表符

例如匹配

/..\n\n

在这里插入图片描述

实际上\n\n会匹配到连续两个换行,但是由于空白没有高亮显示,所以匹配上了空了一行的文本的末尾

实际上如果没有..,单纯的匹配空白字符,将不会有任何高亮显示(至少在vscode的vim插件中是这样的)


匹配数字 / 非数字

前面我们讲过,可以使用[ ]或者[^ ]元字符来匹配或者不匹配指定区间的字符

所以实际上可以用[0-9]或者[^0-9]来匹配数字或字母或者数字与非字母

但是我们可以使用\d元字符来匹配任意一个数字,使用\D元字符来匹配任意一个非数字

例如

/.\d\D[A-Z]..

在这里插入图片描述

匹配数字或字母 / 非数字与字母

\D\d元字符一样, 我们可以使用\w元字符来匹配任意一个数字或字母(等价于[a-zA-Z]),使用\W来匹配任意一个非数字与字母(等价于[^a-zA-Z])

例如

/.\w\W\...

在这里插入图片描述


匹配任意的空白字符 / 非空白字符

我们可以使用\s元字符来匹配任意一个空白字符(等价于[\f\n\r\t\v]),或者使用\S元字符匹配任意一个非空白字符(等价于[^\f\n\r\t\v])

例如

/.\s[A-Z]

在这里插入图片描述


使用POSIX字符类

POSIX是一种也输得标准字符类集,许多正则表达式都支持的一种特殊的字符集合的简写形式

下面列出12个常用的POSIX字符类

字符类说明
[:alnum:]任何一个数组或字母,等价于\w[0-9a-zA-Z]
[:alpha:]任何一个字母,等价于[a-zA-Z]
[:blank:]空格或者制表符,等价于[\t ]
[:cntrl:]ASCII控制字符(ASCII0-ASCII31,以及ASCII127)
[:digit:]任何一个数字,等价于`[0-9
[:print:]任何一个可打印的字符
[:graph:]同[:print:],但是不包含空格
[:lower:]任何一个小写字母
[:upper:]任何一个大写字母
[:punct:]任何一个不是[:alnum:],也不是[:cntrl:]的任意一个字符
[:space:]任何一个空白字符,包括空格
[:xdigit:]任何一个十六进制数字,等价于[a-fA-F0-9]

不过vscode上的vim插件好像不支持使用POSIX字符类,因此这里使用原版的vim,使用:set hlsearch命令高亮搜索

此外,POSIX类字符必须放在[ ]

例如

/[[:alnum:]][[:space:]]

在这里插入图片描述


重复匹配一个或多个字符

有的时候我们想要进行重复匹配某个字符或者字符集合,我们可以直接使用+元字符

但是注意,+元字符至少会匹配一个字符

例如

/ht+p

在这里插入图片描述


匹配零个或多个字符

+可以重复匹配一个或多个字符,那么如果我们想要重复匹配一个可有可无的字符怎么办?

我们可以使用*元字符,*元字符的作用就是其前面的字符可选你

例如

/ht*

在这里插入图片描述

这里*t变成可选的匹配,所以我们能看到匹配了h,H,ht,htt


匹配零个或一个字符

*元字符可以让前一个字符变为可选,同时可以进行多次重复匹配

类似,?元字符可以让前一个字符变为可选,同时可以进行一次匹配

例如

/versions?

在这里插入图片描述

这里能看到,我们匹配到了versionversions两个对象

事实上,为了能够使得?元字符匹配的对象突出,我们通常把要匹配的对象用单独的[ ]元字符包括起来

/ht+p[s]?

指定重复匹配的次数

前面用来重复匹配的元字符,都只能实现指定次数的匹配,没法实现我们需要的次数的匹配

例如我们需要匹配RGB值的模式是三组六位十六进制数字(如FFFFFF),如果我们使用*的话,将无法高效的匹配到我们需要的字符

为此我们可以使用{ }元字符来指定匹配的次数

使用的语法如下

待匹配的元字符{最低匹配次数,最高匹配次数}
或
待匹配的元字符{指定的匹配次数}
或
带匹配的元字符{至少匹配的次数,}

例如我们匹配版本号

/\d{1,2}\.\d{1,2}\.\d{1,2}

在这里插入图片描述

防止过度匹配

+*元字符都是贪婪型的元字符,所以其匹配行为是越多越好,例如我们要匹配<b></b>两个标签之间的全部内容

匹配的文本是:

<b> JACK </b> this is a trial. <b> Lucy <\b>

我们使用如下正则表达式匹配

<[Bb]>.*<\/[Bb]>

但是匹配的效果却是

在这里插入图片描述

我们发现尽管我们只想要匹配两个<b></b>之间的内容,但是却把这一句话全部匹配上了

这就是因为+*是贪婪的元字符,他们会尽可能的向后匹配到符合要求的字符串

为此,我们可以使用贪婪型元字符的懒惰型模式,匹配到第一个结果后将停止

贪婪型元字符对应的懒惰型元字符
**?
++?
{n,}{n,}?

所以我们使用下面的正则表达式来匹配

/<[Bb]>.*?<\/[Bb]>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qYa3E0dl-1595774483475)(图片/2020-07-25 18-16-00 的屏幕截图.png)]


匹配边界

我们前面说过,如果我们匹配cat的话,不仅会匹配到cat,还会匹配到所有包含cat的单词.

如果我们只想匹配到单个的cat单词,那么这个时候就需要实用边界匹配

我们可以是用\b元字符来匹配单词的边界(实际上匹配的是单词间的分隔),例如

/\bas\b

在这里插入图片描述
可以看到即便是bash这类含有as的单词并没有被选中,仅仅选中了as单词


匹配字符串边界

在正则表达式介绍中,我们说到一个文档实际上是一整个非常长的字符串,其中的字符包括可视的abc等字母数字,也包括控制格式的控制字符

匹配字符串边界实际上指的就是匹配每一段的的开头或结尾,例如HTML文档中位于行首的<HTML>标签

^元字符表示字行开头,$元字符代表行结尾

例如

/^[ ]+echo

表示仅匹配开头具有多个空格以及echo

在这里插入图片描述

我们再匹配在行尾的bashrc

/bashrc$

在这里插入图片描述


划分子表达式

在一个单一的正则表达式中,每一个元字符会被视作一个实体(entity)

但是有的时候我们却希望几个元字符组合在一起被视为一个实体(entity)

例如我们想要查找一个IP地址.对IP地址分析后发现IP地址连同点可以分为四个部分,每个部分可能有一到三个数字加上一个点

为此我们可以使用如下的正则表达式

/[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}

实际上上面最关键的部分就是[\d]{1,3}\.,我们把这一部分重复了三次

我们于是希望能够对[\d]{1,3}\.整体指定重复三次,即{3}

但是{ }元字符仅会对前面的一个实体进行三次重复查找,所以直接在[\d]{1,3}\.后面加上{3}是不可以的

为此我们需要使用元字符( )来划分子表达式,将其中的所有内容视为一个实体,得到正则表达式如下

/([\d]{1,3}\.){3}[\d]{1,3}

例如我们匹配所有的网址,网址的每一个层级之间是用/分开的,所以我们可以使用下面的正则表达式匹配

/ht+ps?:\/+([\S]){1,}

在这里插入图片描述

但是每中不足的是这里网址最后包含了并不是网址内容的),因为我们使用了匹配非空白字符,所以)也会被匹配上

我们可以修改匹配内容来避免匹配到),或者可以使用后面的向前查看来匹配到)之前


选择匹配

在这里插入图片描述

我们可以使用|元字符来匹配两个指定的字符串

例如

/echo|pyenv

结合前面的划分子表达式,我们可以实现很多强大的功能

前面匹配IP地址的例子,我们只能实现格式上的匹配,即匹配到xxx.xxx.xxx.xxx

而一个有效的IP地址有如下的要求:

  1. 有一组为一位或两位数组
  2. 有一组以1开头的三位数字
  3. 有一组以2开头,第二位数字在0~4之间的三位数字
  4. 有一组以25开头,第三位在0~5之间的三位数字

所以我们使用如下的正则表达式来匹配有效的IP地址

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

需要注意的是,|的匹配模式是当多个表达式都满足子表达式时,会选择首先满足的子表达式

例如如果是

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

那么以12.159.46.200为例

最后一组200的20符合第一个子表达式(\d{1,2}),同时整体又符合(2[0-4]\d)这个子表达式

但是最终建会优先匹配上第一个符号要求的表达式,即只会选择12.159.46.20


引用匹配

有的时候我们希望能够匹配到成对出现的字符串及之间的内容

例如匹配HTML中的各种标题标签<h1>xxx</h1>

如果直接用下面的表达式

<[Hh][1-6]>*?<\/[Hh][1-6]>

这样除了我们预期的标题标签会被匹配到外,想<h1>xxxx</h2>这样的错误的标题标签也会被匹配到

对此我们希望成对的匹配内容,例如<h1>xxx</h1?

为此,一个可用的解决方案就是引用前面已经匹配到的内容

即我们使用<[Hh][1-6]>匹配到前面的<h1>之后,在后面再次匹配已经匹配到的<h1>

我们使用\数字来引用已经匹配到的子表达式

例如

/<([Hh][1-6])>*?<\/\1>

其中跟着的数字表示已经匹配到的子表达式的次序,除了\1以外还可以使用\2,\3

我们匹配markdown中的高亮**xxx**

/(\*+)\1

在这里插入图片描述

向前查看

向前查看是指我们按照指定格式一直匹配到我们指定的字符

向前查看的元字符是?=,需要放在( )中作为一个子表达式

例如我们匹配所有网址中的协议,即httphttps

/.{0,5}(?=(:\/))

在这里插入图片描述


向后查看

和向前查看同理,向后查看表明从指定位置后开始匹配

向前查看的元字符是?<=,同时也需要放在同一个子表达式中

例如我们匹配网址中的主机名,即:之后到第一个\的内容

/(?<=(:\/\/)).+?(?=\/)

在这里插入图片描述

所以结合向前向后查看,我们就可以查找任意指定的内容


嵌入式条件

我们可以在正则表达式中嵌入条件,来进行匹配

例如我们需要匹配电话号码时,前四位可以用括号括起来,例如(0915)或0915都是正确的

但是如果是(0915)的话电话号码格式就是(0915)xxxxx,如果是0915的话,电话号码格式就是0915-xxxxx

这个时候我们可以用选择匹配来匹配两个子表达式,但更方便的是,我们可以使用嵌入式条件,当电话号码开头为(0915)时,匹配(0915)xxxxx

当电话号码开头为0915时,匹配0915-xxxxx

类似于任何一门编程语言,我们使用条件判断语句时候有三个重要的组成:

  1. 判断条件
  2. 条件成立时的操作
  3. 条件不成立时的操作

其中条件不成立时的操作是可选的

类似的,正则表达式的条件也分为作为条件的语句,条件语句存在时匹配的语句,条件语句不存在时匹配的语句

正则表达式中,用于表示条件语句的元字符是( )?

我们可以使用(?(数字)成功匹配时匹配的字符|未成功匹配时匹配的字符)来完成后续匹配

类似于上面说的,条件不成立时的操作可以省略掉,此时后续匹配为(?(数字)成功匹配时的字符)

所以上面匹配座机号,可以使用如下的正则表达式

(\()?\d{4}(?(1)\)|-)\d{5}

上面的正则表达式中(\()?用于匹配(,当(存在时(即第一个匹配存在时),将会匹配对应的)右括号,否则将匹配-连字符

条件查看

前面分别讲解了向前查看和向后查看,实际上我们可能需要使用到条件查看

例如,美国邮编有两种形式,分别为五位数字的ZIP编码或者是xxxxx-xxxx的ZIP+4编码

这样的话,我们的环视就需要以-连字符为条件进行环视,当-不存在则终止匹配,存在时匹配-xxxx

条件查看的语句为(?(?=查看的字符)查看字符不存在时匹配的字符)

所以匹配美国邮编的正则表达式为

\d{5}(?(?=-)-\d{4})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值