常见的元字符
-
\b
不消耗任何字符,匹配单词的开始或者结尾 -
.
匹配除了换行符之外的任意一个字符 -
\d
匹配一个数字 -
\s
匹配任意的空白字符,包括空格,制表符,换行符 -
\w
匹配一个字母,包括字符,下划线,汉字等 -
^
匹配字符串的开头 -
$
匹配字符串的结尾
常见的用于重复的元字符
-
*
指定前面的内容(字符或者分组)可以重复任意多次, -
+
指定前面的内容(字符或者分组)至少要重复1一次 -
?
指定前面的内容(字符或者分组)重复0次或者1次 -
{n}
重复n次 -
{m,n}
重复至少m次,最多n次 -
{m,}
重复至少m次,最多无穷次
中括号[]
匹配[]
中的任意一个,单字符匹配
[]
中没有元字符,所有的元字符在[]
中都会失去意义,只有五个特殊字符^ - \ [ ]
.
先详解一下这五个特殊字符的作用
-
因为
[ 和 ]
本身和正则表达式[]
冲突,所有如果要在[]
中匹配[
和]
,需要对他们进行转义 -
因为
\
是用来转义的,如果我们不对\
转义,它就会对别人转义,所以如果要在[]
中匹配\
本身,我们需要使用\\
-
-
在[]
中用来代表一个范围,比如[0-9]
,[a-z]
,当-
挨着[
或者]
的时候,-
表示它的字面意思,比如
[-abc]
会匹配-
,a
,b
,c
中的任意一个
[a-c]
会匹配a b c
中的任意一个
[a\-c]
会匹配a
,-
,c
这三个中的任意一个 -
^
只有在[]
中的最开始才有特殊含义,表示排除,否则也是表示它的字面意思。比如
[^0-9]
匹配不包含0-9的任意字符。
如果^
在[]
中的其他位置,就会只表示它的字面意思了。
比较常见的错误是[http|https]
,我们的本意是要匹配http或者https中的任意一个,但其实这个正则表达式和[ht|ps]
是一模一样的,表示匹配h
,t
,p
,|
,s
中的任意一个。
要达到上面的效果,我们可以这样写(http|https)
,或者https?
。
另外,当我们使用|
的时候,一定要使用()
进行限定,否则会出现各种各样奇葩的问题,因为|
的匹配范围是从左到右,知道结束或者遇到)
为止。
分支条件
|
使用分支条件一定要使用()
括起来,而且分支是短路的,只要符合其中的一个,就不会继续匹配分支中的其他条件了。
反义,匹配不满足某个条件的字符串
-
\W
匹配任意不是字母,数字,下划线的字符 -
\S
匹配任意非空白字符 -
\D
匹配任意非数字的字符 -
\B
匹配任意的非单次开头或者结尾的位置 -
[^abc]
匹配不是a
,b
,c
的任意字符
分组
()
默认会给每一个分组一个分组号,从1开始分配,0代表整个正则表达式,我们可以在稍后通过分组号来引用前面的分组,比如\1
代表引用第一个分组匹配到的内容,\n
代表引用第n个分组匹配到的内容
我们也可以给分组指定一个名称,在稍后可以通过这个名称来引用前面的分组,具体的做法是(?<name>expr)
,或者(?'name'expr)
,把这个分组的名字命名为name,在后面引用的时候可以\k<name>
来进行引用。
举几个例子加深印象。
\b(\w+)\b\s+\1\b
,可以匹配任意的重复单次,比如go go
,good good
等。这个表达式首先是一个单词,也就是单词开始处和结束处之间的多于一个的字母或数字\b(\w+)\b
,这个单词会被捕获到编号为1的分组中,然后是1个或几个空白符\s+
,最后是分组1中捕获的内容(也就是前面匹配的那个单词)\1
。
其中\1
就是引用的第一个分组匹配到的内容。
上面的例子也可以写成这样
\b(?<name>w+)\b\s+\k<name>\b
,这个表达式首先是一个单词,然后这个单次被捕获到了名字为name的分组中,在后来这个分组被引用了。
我们也可以通过(?:expr)
来将expr分组,但是不给它分配组号,这多用于我们确定不会在以后引用这个分组的内容的情况下。
断言
断言和\b
,^
,$
一样,匹配一个位置,这个位置满足一定的条件。
-
正预测断言
(?=expr)
断言一个位置,这个位置后面满足expr。比如\b\w+(?=ing\b)
,这个正则表达式匹配以ing结尾的单词的前半部分,比如dacing,会匹配到dac. 这个正则表达式的意思是,首先是一个单词,这个单次后面跟着ing -
正回顾断言
(?<=expr)
断言一个位置,这个位置前面满足expr,比如(?<=\bre)\w+\b
,这个表达式的意思是,首先是一个单词,这个单次的前面是re,比如reading,会匹配到ading. -
负预测断言
(?!expr)
断言一个位置,这个位置后面不满足expr,。主要用去确保被匹配的字符串中不会出现一些字符,比如我们想要匹配这样一个字符串,它以hello开头,但是没有出现good,我们可以这样写
\bhello.*(?!good)\w*\b
-
负回顾断言
(?<!expr)
断言一个位置,这个位置前面不满足expr.比如(?<![a-z])\d{7}
,可以匹配不以小写字母开头的7位数字。
可以看一下很实用的例子
(?<=<(\w+)>).*(?=<\/\1>)
,这个可以用来匹配HTML标签中的内容,具体如下,首先是一个断言(?<=<(\w+)>)
,断言一个位置,这个位置前面是类似<body>
这样的标签,然后是任意的字符,接下来又是一个断言(?=<\/\1>)
,断言这个位置后面是能匹配到前面那样的标签内容,只是多了一个反斜杠,比如<\body>
贪婪域懒惰
默认正则表达式是贪婪的,会尽可能多的匹配,比如字符串aabab
,如果使用正则表达式a.*b
去匹配的话,会匹配到整个字符串。
有时候我们需要懒惰匹配,要尽可能少的匹配,这时候我们就需要在前面提到的用于重复的元字符后面加一个?
,比如*?
,+?
,??
,{n,m}?
,{n,}?
平常工作中能用到的正则表达式大概就是这些了。
网友评论