正则表达式详解

正则表达式详解

正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。

许多程序设计语言都支持利用正则表达式进行字符串操作。例如,在Perl中就内建了一个功能强大的正则表达式引擎。正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。所有我们可以通过grep来学习正则。

一、位置匹配

我们通过一个例子来实践一下正则,示例如下:

[root@all shell]# cat regex 
hello world
hi hello
hello acd
[root@all shell]# grep "hello" regex 
hello world
hi hello
hello acd
[root@all shell]# grep "^hello" regex 
hello world
hello acd

如上例所示,我们通过grep可以搜索出文本中包含hello的行。但是如果要搜索以hello开头的行,只需要使用正则表达式。在正则表达式中,^表示锚定行首。所以"^hello"表示只匹配位于行首的hello字符串。

^在正则中表示锚定行首,$在正则中表示锚定行尾。所以在上例的文本中,我们可以通过"hello$",去匹配位于行尾的hello字符串。示例如下:

[root@all shell]# grep "hello$" regex 
hi hello

既然 ^ 和 $分别表示锚定行首和行尾,那么将他们结合在一起使用。"^hello$"就表示hello字符串既位于行首,又位于行尾。也就是说,整行只有一个hello。示例如下:

[root@all shell]# cat regex 
hello world
hi hello
hello acd
hello
[root@all shell]# grep "^hello$" regex 
hello

如上所示,我们成功匹配到了文本的第四行,并将第四行打印了出来。那么如果想匹配空行呢,这时候就可以用"^$"了,我们插入一个空行来演示一下:

[root@all shell]# grep "^$" regex 

如上所示,空行被匹配出来。注意,含有空格的行不叫空行。、

现在,我们已经可以锚定行首和行尾了。那么如何锚定词首和词尾呢。在正则表达式中,"<"表示锚定词首,">"表示锚定词尾。我们再准备一个文本文件来进行测试,内容如下:

[root@all shell]# cat REG 
abchello world
abc helloabc abc
abc abchelloabc abc

上图中,abchello包含helloi字符串,但是hello字符串位于这个单词的词尾。同样helloabc字符串中hello位于这个单词的词首。我们来实验一下:

[root@all shell]# grep "<hello" REG 
abc helloabc abc
[root@all shell]# grep "hello>" REG 
abchello world

如上例所示,"<hello"表示hello作为词首的单词会被匹配到,"hello>"表示hello作为词尾的单词会被匹配到。

同样的,我们把"<"和">"结合起来使用一下,示例如下。我们在REG文本中再添加一行。

[root@all shell]# cat REG 
abchello world
abc helloabc abc
abc abchelloabc abc
abchello helloabc hello ahelloa
[root@all shell]# grep "<hello>" REG 
abchello helloabc hello ahelloa

上例中,"<hello>"表示hello既是词首又是词尾时会被匹配到。也就是说,当hello作为一个独立的单词时,才会被匹配到。其实在正则表达式中,除了"<"和">"能够表示锚定词首和词尾以外,我们还可以使用""去代替"<"和">"。""技能锚定词首,又能锚定此尾。示例如下:

[root@all shell]# cat REG 
abchello world
abc helloabc abc
abc abchelloabc abc
abchello helloabc hello ahelloa
[root@all shell]# grep "hello" REG 
abc helloabc abc
abchello helloabc hello ahelloa
[root@all shell]# grep "hello" REG 
abchello world
abchello helloabc hello ahelloa
[root@all shell]# grep "hello" REG 
abchello helloabc hello ahelloa

和""相反的,还有一个"B"。他们刚好相反,""是用来锚定词首和词尾的,也就是说""是用来匹配单词边界的,而"B"是用来匹配非单词边界的。示例如下:

[root@all shell]# grep "Bhello" REG 
abchello world
abc abchelloabc abc
abchello helloabc hello ahelloa

上例中,"Bhello"表示只要hello不是词首,就会被匹配到。

在正则表达式中,有基础正则表达式和扩展正则表达式之分。有些符号在基础正则表达式和扩展正则表达式是同样的,有些则不通用。比如上文中提到的这些符号都是通用的。上文中用到的正则表达式都与位置有关,比如,行首、行尾、词首、词尾。我们可以把这些符号理解为与位置有关的正则表达式。

总结:

^ 表示锚定行首,此字符后面的任意内容必须出现在行首,才能匹配

$ 表示锚定行首,此字符前面的任意内容必须出现在行尾,才能匹配

 ^$ 表示匹配空行。空行表示回车,而空格和tab键都不加空行

^abc$  表示abc独占一行时,会被匹配到。

<或者  匹配单词边界,表示锚定词首,其后面的单词必须作为词首出现

>或者  匹配单词边界,表示锚定词尾,其后面的单词必须作为词尾出现

B  匹配非单词边界,与刚好相反

二、连续次数的匹配

第一小章节详细描述了位置匹配,第二章,我们来了解一下连续次数的匹配。还是通过一次例子来看,如果我们想在一个文件中找到那些行包含连续的两个字母a。需要怎么做呢?示例如下:

[root@all shell]# cat -n regex.txt 
     1    a a
     2    aa
     3    a aa
     4    bb
     5    bbb
     6    c c ccc
     7    dddd d dd ddd
     8    ab abc abcc
     9    ef eef eeef
[root@all shell]# grep -n "aa" regex.txt 
2:aa
3:a aa
[root@all shell]# grep -n "a{2}" regex.txt 
2:aa
3:a aa

如上例所示,可以直接使用grep命令,在文本中搜索aa即可,因为aa就是两个连续的a字母。但是如果想要搜索10个或更多个a字母,这种方式就显得很麻烦。我们可以利用正则来解决,如上图中的第二种方式。"{2}"就表示连续出现两次,同样的"{n}"就表示连续出现n次。

不过需要注意的是,如果字符出现的次数大于指定的次数,也是会被匹配到的。示例如下:

[root@all shell]# grep -n "b{2}" regex.txt 
4:bb
5:bbb

如上所示,第4行字母b连续出现了两次被匹配到了,第5行,b字母连续出现了3次,包含两次,所以前两个连续的字母b也被匹配到了。如果只想精确的匹配两次。我们可以结合第一章介绍的方法,示例如下:

[root@all shell]# grep "<b{2}>" regex.txt 
bb

我们再来延伸一下,"{x,y}"表示之前的字符至少连续出现x次,至多出现y次。也就是说,只要之前的字符连续出现次数在x和y次之间,都会被匹配到。示例如下:

[root@all shell]# grep -n --color "d{2,4}" regex.txt 
7:dddd d dd ddd

如上所示,连续出现了2次,3次,4次的d字母都被匹配到了。总结一下:

{x}表示之前的字符连续出现x次会被匹配到

{x,y}表示之前的字符至少连续出现x次,至多出现y次,都会被匹配到。

{x,}表示之前的字符至少连续出现x次,或者连续出现次数大于x次,会被匹配到,上不封顶

{,y}表示之前的字符至多连续出现y次,或者连续出现次数小于y次,会被匹配到,最小为0次。(红帽6会报错重复定义次数不完成,该方式待验证,可以写成{0,y})

现在我们再来认识一个用于匹配次数的正则符号,就是*。在通配符中,*表示匹配任意长度的任意字符。但是在正则表达式中,*表示之前的字符连续出现的任意次数,(包括0次)。示例如下:

[root@all shell]# cat -n regex.txt 
     1    a a
     2    aa
     3    a aa
     4    bb
     5    bbb
     6    c c ccc
     7    dddd d dd ddd
     8    ab abc abcc
     9    ef eef eeef
[root@all shell]# grep -n --color "e*f" regex.txt 
9:ef eef eeef

上例中,e*f表示e出现任意次,f必须跟在e后边。

注意:*表示之前的字符出现任意次数,包括0次。我们再看一个例子:

[root@all shell]# grep -n --color "d*" regex.txt 
1:a a
2:aa
3:a aa
4:bb
5:bbb
6:c c ccc
7:dddd d dd ddd
8:ab abc abcc
9:ef eef eeef

如上所示,d*表示字母d出现任意次数。即可被匹配到,所以第7行会被高亮显示。但是其他行也被打印了出来,这是因为*表示出现任意次数,包括0次。其他行中,没有字符d,也就是说d出现了0次,所以其他行也符合条件。

在通配符中,*表示匹配任意长度的任意字符。在正则中,可以用".*"表示任意长度的任意字符。通过示例来看一下:

[root@all shell]# cat -n regex.txt 
     1    a a
     2    aa
     3    a aa
     4    bb
     5    bbb
     6    c c ccc
     7    dddd d dd ddd
     8    ab abc abcc
     9    ef eef eeef
[root@all shell]# grep -n --color "a.*" regex.txt 
1:a a
2:aa
3:a aa
8:ab abc abcc
[root@all shell]# grep -n --color "ee." regex.txt 
9:ef eef eeef
[root@all shell]# grep -n --color "ee.." regex.txt 
9:ef eef eeef

如上所示,a字母后边存在任意长度的任意字符,都可以被匹配到。其实,在正则表达式中,"."表示匹配任意单个字符。在上例的第二和第三例子中,"ee."表示ee后面跟随任意一个单个字符,都会被匹配到。"ee.."表示ee后边跟随任意两个单个字符都会被匹配到。由于空格也算单个字符,所以eef 也被匹配到了。

".*"可以理解为.和*的结合,理解为连续出现任意次的任意单个字符。

我们再来看两个新符号, "?"和"+"

? 表示匹配前面的字符0次或1次,也就是说,前面的字符要么没有,要么有一个。

+ 表示匹配其前面的字符至少一次。也就是说,前面的字符必须至少有一个。

[root@all shell]# grep --color "abc?" regex.txt 
ab abc abcc
[root@all shell]# grep --color "abc+" regex.txt 
ab abc abcc

如上例所示,"c?"表示c出现0次或1次。所以ab和abc都被匹配到了。"c+"表示c至少出现一次,连续次数上不封顶,所以abc和abcc都被匹配到了。

总结:

*  表示前面的字符出现任意次,包括0次。

.   表示任意单个字符

.*  表示任意长度的任意字符

?  表示匹配前面的字符0次或1次

+  表示匹配其前面的字符至少一次

{n}  表示前面的字符连续出现n次,就会被匹配到。

{x,y}表示之前的字符至少连续出现x次,至多出现y次,都会被匹配到。

{x,}表示之前的字符至少连续出现x次,或者连续出现次数大于x次,会被匹配到,上不封顶

{,y}表示之前的字符至多连续出现y次,或者连续出现次数小于y次,会被匹配到,最小为0次

三、常用符号

 在上一个章节我们提到".",表示匹配任意单个字符。例如"a.."表示只要a字母后边跟任意三个字符,就可以被匹配到。如果我们想做的更细致一些,例如我们对字母a后边跟的3个字符有要求,不能是任意三个字符,必须是三个字母。这时候我们就需要引入新的符号"[[:alpha:]]"。

在正则表达式中,"[[:alpha:]]"表示任意字母,不区分大小写。示例如下:

[root@all shell]# cat reg1 
a
a6d
a89&
a7idai8
abcd
aBdc
aBCD
a123
a1a3
a&@%
[root@all shell]# grep --color "a[[:alpha:]]{3}" reg1
abcd
aBdc
aBCD

上例中,"[[:alpha:]]{3}"表示3个任意的连续字母。所以就是字母a后边跟了3个字母才会被匹配到,如果包含非字母,如数字和特殊符号就不会被匹配到。如果我们把要求再细化一点。要求a后边必须跟3个小写字母,这时候我们引出了另一个符号"[[:lower:]]"。同样对应的还有大写字母"[[:upper:]]"。示例如下:

[root@all shell]# grep --color "a[[:lower:]]{3}" reg1 
abcd
[root@all shell]# grep --color "a[[:upper:]]{3}" reg1 
aBCD

 这时候,你一定发现了一些规律。只要替换"[[: :]]"中的单词,就可以表示不同的含义。我们来总结一下:

[[:alpha:]]       表示任意大小写字母

[[:lower:]]       表示任意小写字母

[[:upper:]]      表示任意大写字母

[[:digit:]]         表示0到9之间的任意单个数字,包括0和9

[[:alnum:]]      表示任意数字或字母

[[:space:]]      表示任意空白字符,包括空格,tab键等

[[:punct:]]       表示任意标点符号

 除了以上列举出来的以外,还有一些"[a-z]"也是能够表示任意单个小写字母,和[[:lower:]]是等价的。同样的还有"[A-Z]"表示任意单个大写字母。"[a-zA-Z]"表示任意字母,不区分大小写。"[0-9]"表示0到9之间任意单个数字。

其实,以上各种符号中的方括号也是有特殊的含义的。"[ ]"表示匹配指定范围内的任意单个字符,示例如下:

[root@all shell]# cat reg2
bc
bd
be
bf
bg
[root@all shell]# grep --color "b[ceg]" reg2
bc
be
bg

如上所示,字母b后面跟随c e 或g,都可以被匹配到。"[ ]"表示匹配指定范围内的任意字符,也就是说,字符和方括号内的任意一个字符相同,都可以被匹配到。理解了"[ ]"的含义,还有一个相反的就是"[^ ]"。"[^ ]"表示指定范围外的任意单个字符,它与"[ ]"的含义正好相反。示例如下:

[root@all shell]# cat reg4
fa
fb
fc
fd
fe
ff
fg
[root@all shell]# grep --color "f[^aceg]" reg4
fb
fd
ff

如上所示,只要字母f后面跟的不是a c e g,其他的都可以被匹配到。相当于被排除了 a c e  g这几个字母。同样的,还有以下几种符号:

[^0-9] 或 [^[:digit:]]  表示非数字的单个字符可以被匹配到

[^a-z]  或 [^[:lower:]]  表示非小写字母的单个字符可以被匹配到

[^A-Z]   或 [^[:upper:]]   表示非大写的单个字符可以被匹配到

[^a-zA-Z]  或 [^[:alpha:]]   表示非字母的单个字符可以被匹配到

[^a-zA-Z0-9]  或 [^[:alnum:]]  表示非字母非数字的单个字符可以被匹配到,比如特殊符号

其实:不仅[0-9]和[[:digit:]],还有一些简写的符号也可以表示数字,比如"d"。但是,并不是所有的正则表达式处理器都可以识别这些简写格式。示例如下:

[root@all shell]# cat reg5 
e1
ea
e7
eY
e$
e8
e8
[root@all shell]# grep --color "e[[:digit:]]" reg5 
e1
e7
e8
e8
[root@all shell]# grep --color "e[0-9]" reg5 
e1
e7
e8
e8
[root@all shell]# grep --color "ed" reg5

如上所示,在默认情况下,grep就无法识别"d"这种简短格式。所以没匹配到任何结果。如果想要grep可以识别这种简短格式,可以使用-P选项,表示grep使用兼容perl的正则表达式引擎。示例如下:

[root@all shell]# grep --color "ed" reg5 
[root@all shell]# grep -P --color "ed" reg5 
e1
e7
e8
e8

在此处,再列出一些常用的简写的格式符号。

d   表示任意单个0到9的数字

D   表示任意单个非数字字符

    表示匹配单个横向制表符

s    表示匹配单个空白字符

S    表示匹配单个非空白字符

总结:

.   表示匹配任意单个字符
*  表示匹配前面的字符任意次,包括0次

[  ]    表示匹配指定范围内的任意单个字符
[^  ]   表示匹配指定范围外的任意单个字符
 
[[:alpha:]]  表示任意大小写字母
[[:lower:]]  表示任意小写字母
[[:upper:]]  表示任意大写字母
[[:digit:]]  表示0到9之间的任意单个数字(包括0和9)
[[:alnum:]]  表示任意数字或字母
[[:space:]]  表示任意空白字符,包括"空格"、"tab键"等。
[[:punct:]]  表示任意标点符号
 
[0-9]与[[:digit:]]等效
[a-z]与[[:lower:]]等效
[A-Z]与[[:upper:]]等效
[a-zA-Z]与[[:alpha:]]等效
[a-zA-Z0-9]与[[:alnum:]]等效
 
[^0-9]与[^[:digit:]]等效
[^a-z]与[^[:lower:]]等效
[^A-Z]与[^[:upper:]]等效
[^a-zA-Z]与[^[:alpha:]]等效
[^a-zA-Z0-9]与[^[:alnum:]]等效
 
#简短格式并非所有正则表达式解析器都可以识别
d 表示任意单个0到9的数字
D 表示任意单个非数字字符
 表示匹配单个横向制表符(相当于一个tab键)
s表示匹配单个空白字符,包括"空格","tab制表符"等
S表示匹配单个非空白字符

 四、分组和向后引用

本章节中,我们来了解以下分组和向后引用。我们先来看下分组,先看一个例子:

[root@all shell]# cat reg6
hello
helloo
hellooo
hellohello
[root@all shell]# grep --color "hello{2}" reg6
helloo
hellooo

上例中,我们使用了连续次数匹配。{2}表示其前面的字符连续出现两次,即可被匹配到。但是它只能影响前面的单个字符,也就是上例中的字母o。这时,如果想要找出两个连续的hello字符串。这时候我们就需要用到分组,把hello当成一个整体,示例如下:

[root@all shell]# cat reg6
hello
helloo
hellooo
hellohello
[root@all shell]# grep --color "(hello){2}" reg6 
hellohello

如上所示,"(hello)"表示将hello字符串当成一个整体。所以"{2}"影响的就是前面的hello字符串。"( )"就是分组,表示将其中的内容视为一个整体。

分组还可以嵌套,我们再来看一个例子:

[root@all shell]# cat -n reg7 
     1    abefef
     2    abefefabefef
[root@all shell]# grep -n --color "(ab(ef){2}){2}" reg7 
2:abefefabefef

现在我们再说说向后引用,如果想实现向后引用,必须以分组为前提。我们先来看示例:

[root@all shell]# clear
[root@all shell]# cat reg8 
Hello world Hello
Hiiii world Hiiii
Hello world Hiiii
[root@all shell]# grep --color "H.{4} world H.{4}" reg8 
Hello world Hello
Hiiii world Hiiii
Hello world Hiiii

上例中,"H.{4}"表示大写字母H后面跟随了4个任意字符。其中"."表示任意单个字符。所以"H.{4}"既匹配到了Hello,又匹配到了Hiiii。

现在,如果只想从上例中找到 world 单词前后相同的那些行。也就是说 world前边的单词和后边的单词要一致。那么第三行明显就不满足条件。如何筛选出来呢,这时候就需要用到向后引用,示例如下:

[root@all shell]# cat reg8 
Hello world Hello
Hiiii world Hiiii
Hello world Hiiii
[root@all shell]# grep --color "(H.{4}) world 1" reg8 
Hello world Hello
Hiiii world Hiiii

使用上述正则,即可达到我们的目的。"(H.{4})"是一个分组,表是字母H后边随意跟了4个字符,并且H和这4个字母作为一个整体。添加分组是因为想实现向后引用,必须以分组为前提。"1"表示整个正则中第一个分组中的正则所匹配到的结果。也就是说,"1"引用了整个正则中第1个分组的正则所匹配的结果。

"1"表示表示引用整个正则中第1个分组中的正则所匹配到的结果。同样的,

"2"表示表示引用整个正则中第2个分组中的正则所匹配到的结果。以此类推....... 示例如下:

[root@all shell]# cat reg9
Hello world Hiiii -- Hiiii
Hiiii world Hello -- Hello
Hello world Hcccc -- Haaaa
[root@all shell]# grep --color "(H.{4}) world (H.{4}) -- 2" reg9
Hello world Hiiii -- Hiiii
Hiiii world Hello -- Hello

如果当分组进行嵌套时,应该怎么区分第1个分组和第2个分组。答案是分组的顺序取决于分组符号左侧的顺序。例如,一个分组中嵌套了另一个分组。这时"1"代表的外层分组,"2"代表内层分组。因为外层分组的左侧在最前边。

总结:

( )   表示分组,我们可以将其中的内容当成一个整体,分组可以嵌套。

1     表示引用整个正则表达式中第1个分组中的正则匹配到的结果

2     表示引用整个正则表达式中第2个分组中的正则匹配到的结果

 五、转义符

我们再来认识一个常用符号,它就是反斜杠""。转义字符,我们通过一个小例子看一下:

[root@all shell]# cat reg10
bae
a1#
ddd
a-!
ccc
a..
[root@all shell]# grep --color "a.." reg10
a1#
a-!
a..

如上所示,"a.."表示只要字母a后边跟两个字符,就可以被匹配到。现在我们的需求是想找出以a开头,后边跟两个点的。也是说只找上例中的最后一行。这时候应该使用如下命令:

[root@all shell]# cat reg10
bae
a1#
ddd
a-!
ccc
a..
[root@all shell]# grep --color "a.." reg10
a..

在正则中"."表示任意单个字符,并不表示点本身。如果希望"."只表示点本身,这时候就需要反斜杠来转义。同理,我们如果要匹配 * 本身,使用*即可。

在正则中,? 表示前面的字符出现0次或1次,+ 表示前面的字符出现1次以上。如果想匹配?或+本身,直接使用 ?或 + 就行了。

在某些时候,我们想要匹配 本身。在反斜杠前面加上反斜杠就行了,示例如下:

[root@all shell]# cat reg11 
a
ab
abc
a\
aa
[root@all shell]# grep --color 'a\' reg11
a
a
aa
[root@all shell]# grep --color 'a\\' reg11
a\

上述用的是单引号,而不是双引号。使用双引号会报错。

六、基础正则表达式总结:

对上文中的符号进行总结,总结如下:

#################常用符号#################
.   表示任意单个字符。
*  表示前面的字符连续出现任意次,包括0次。
.* 表示任意长度的任意字符,与通配符中的*的意思相同。
  表示转义符,当与正则表达式中的符号结合时表示符号本身。
[  ]表示匹配指定范围内的任意单个字符。
[^  ]表示匹配指定范围外的任意单个字符。
 
#################单个字符匹配相关#################
[[:alpha:]]  表示任意大小写字母。
[[:lower:]]  表示任意小写字母。
[[:upper:]]  表示任意大写字母。
[[:digit:]]  表示0到9之间的任意单个数字(包括0和9)。
[[:alnum:]]  表示任意数字或字母。
[[:space:]]  表示任意空白字符,包括"空格"、"tab键"等。
[[:punct:]]  表示任意标点符号。
[^[:alpha:]]  表示单个非字母字符。
[^[:lower:]]  表示单个非小写字母字符。
[^[:upper:]]  表示单个非大写字母字符。
[^[:digit:]]  表示单个非数字字符。
[^[:alnum:]]  表示单个非数字非字母字符。
[^[:space:]]  表示单个非空白字符。
[^[:punct:]]  表示单个非标点符号字符。
[0-9]与[[:digit:]]等效。
[a-z]与[[:lower:]]等效。
[A-Z]与[[:upper:]]等效。
[a-zA-Z]与[[:alpha:]]等效。
[a-zA-Z0-9]与[[:alnum:]]等效。
[^0-9]与[^[:digit:]]等效。
[^a-z]与[^[:lower:]]等效。
[^A-Z]与[^[:upper:]]等效
[^a-zA-Z]与[^[:alpha:]]等效
[^a-zA-Z0-9]与[^[:alnum:]]等效
#简短格式并非所有正则表达式解析器都可以识别。
d 表示任意单个0到9的数字。
D 表示任意单个非数字字符。
	 表示匹配单个横向制表符(相当于一个tab键)。
s表示匹配单个空白字符,包括"空格","tab制表符"等。
S表示匹配单个非空白字符。
 
#################次数匹配相关#################
?  表示匹配其前面的字符0或1次
+  表示匹配其前面的字符至少1次,或者连续多次,连续次数上不封顶。
{n} 表示前面的字符连续出现n次,将会被匹配到。
{x,y} 表示之前的字符至少连续出现x次,最多连续出现y次,都能被匹配到,换句话说,只要之前的字符连续出现的次数在x与y之间,即可被匹配到。
{,n} 表示之前的字符连续出现至多n次,最少0次,都会陪匹配到。
{n,}表示之前的字符连续出现至少n次,才会被匹配到。
 
#################位置边界匹配相关#################
^:表示锚定行首,此字符后面的任意内容必须出现在行首,才能匹配。
$:表示锚定行尾,此字符前面的任意内容必须出现在行尾,才能匹配。
^$:表示匹配空行,这里所描述的空行表示"回车",而"空格"或"tab"等都不能算作此处所描述的空行。
^abc$:表示abc独占一行时,会被匹配到。
<或者 :匹配单词边界,表示锚定词首,其后面的字符必须作为单词首部出现。
>或者 :匹配单词边界,表示锚定词尾,其前面的字符必须作为单词尾部出现。
B:匹配非单词边界,与正好相反。
 
#################分组与后向引用#################
( ) 表示分组,我们可以将其中的内容当做一个整体,分组可以嵌套。
(ab) 表示将ab当做一个整体去处理。
1 表示引用整个表达式中第1个分组中的正则匹配到的结果。
2 表示引用整个表达式中第2个分组中的正则匹配到的结果。

七、扩展正则表达式

前面我们提到,在Linux中,正则表达式分为基本正则表达式和扩展正则表达式。在基本正则表达式和扩展正则表达式中,有些符号是通用的。我们先来总结一下通用的符号:

.   表示任意单个字符。
*  表示前面的字符连续出现任意次,包括0次。
.* 表示任意长度的任意字符,与通配符中的*的意思相同。
  表示转义符,当与正则表达式中的符号结合时表示符号本身。
[  ]表示匹配指定范围内的任意单个字符。
[^  ]表示匹配指定范围外的任意单个字符。
 
[[:alpha:]]  表示任意大小写字母。
[[:lower:]]  表示任意小写字母。
[[:upper:]]  表示任意大写字母。
[[:digit:]]  表示0到9之间的任意单个数字(包括0和9)。
[[:alnum:]]  表示任意数字或字母。
[[:space:]]  表示任意空白字符,包括"空格"、"tab键"等。
[[:punct:]]  表示任意标点符号。
[^[:alpha:]]  表示单个非字母字符。
[^[:lower:]]  表示单个非小写字母字符。
[^[:upper:]]  表示单个非大写字母字符。
[^[:digit:]]  表示单个非数字字符。
[^[:alnum:]]  表示单个非数字非字母字符。
[^[:space:]]  表示单个非空白字符。
[^[:punct:]]  表示单个非标点符号字符。
[0-9]与[[:digit:]]等效。
[a-z]与[[:lower:]]等效。
[A-Z]与[[:upper:]]等效。
[a-zA-Z]与[[:alpha:]]等效。
[a-zA-Z0-9]与[[:alnum:]]等效。
[^0-9]与[^[:digit:]]等效。
[^a-z]与[^[:lower:]]等效。
[^A-Z]与[^[:upper:]]等效
[^a-zA-Z]与[^[:alpha:]]等效
[^a-zA-Z0-9]与[^[:alnum:]]等效
 
^:表示锚定行首,此字符后面的任意内容必须出现在行首,才能匹配。
$:表示锚定行尾,此字符前面的任意内容必须出现在行尾,才能匹配。
^$:表示匹配空行,这里所描述的空行表示"回车",而"空格"或"tab"等都不能算作此处所描述的空行。
^abc$:表示abc独占一行时,会被匹配到。
<或者 :匹配单词边界,表示锚定词首,其后面的字符必须作为单词首部出现。
>或者 :匹配单词边界,表示锚定词尾,其前面的字符必须作为单词尾部出现。
B:匹配非单词边界,与正好相反。

上述符号,在基本正则表达式和扩展正则表达式的用法是完全一样的。基本上70%的符号都是通用的。与基本正则表达式相比,剩下的30%反而更简单了。

在基本正则表达式中,{n}表示前面的字符连续出现n次,就会被匹配到。在扩展正则表达式中,{n}表示前面的字符连续出现n次,就会被匹配到。在基本正则表达式中,( )表示分组,(ab)表示将ab当成一个整体处理。在扩展正则表达式中,()表示分组,(ab)表示将ab当成一个整体处理。示例如下:

[root@all shell]# cat reg6 
hello
helloo
hellooo
hellohello
[root@all shell]# grep "(hello){2}" reg6 
hellohello
[root@all shell]# grep -E "(hello){2}" reg6 
hellohello

如上所示,当使用扩展正则表达式时,书写更简单。我们再来总结一下,扩展正则表达式比基本正则表达式的不同之处。在扩展正则表达式中:

()表示分组
(ab)表示将ab当做一个整体去处理
1表示引用整个表达式中第1个分组中的正则匹配到的结果
2表示引用整个表达式中第2个分组中的正则匹配到的结果
?表示匹配其前面的字符0次或1次
+ 表示匹配前面的字符至少1次
{n}表示前面的字符连续出现n次
{x,y}表示之前的字符至少连续出现x次,最多出现y次
{,n}表示之前的字符出现至多n次,做少0次
{n,}表示之前的字符连续出现至少n次,才会被匹配到

看了上述总结,可以发现,扩展正则表达式更符合懒人的习惯,而且,扩展正则表达式的可读性更高。

在扩展正则表达式中,还有一个符号是基本正则表达式中没有的,它就是 "|" 。"|"在扩展正则表达式中表示或,示例如下:

[root@all shell]# cat reg12
zsythink@zsythink.net
1@2
dwfdsfsfs@dwed.net
testregex@163.com
testregex@163zsy.net
testregex@163zsy.org
testregex@163zsy.edu
testregex@163zsy.ttt
a@1.com
testregex@163zsy.cccom
[root@all shell]# grep -E "com$" reg12 
testregex@163.com
a@1.com
testregex@163zsy.cccom
[root@all shell]# grep -E "net$" reg12 
zsythink@zsythink.net
dwfdsfsfs@dwed.net
testregex@163zsy.net

如上所示,我们分别找到文本中以 com 结尾的行和以 net 结尾的行。如果我们想同时找到 com 和 net结尾的行,这时候就需要用到 "|" , 示例如下:

[root@all shell]# grep -E "(com|net)$" reg12 
zsythink@zsythink.net
dwfdsfsfs@dwed.net
testregex@163.com
testregex@163zsy.net
a@1.com
testregex@163zsy.cccom

上例中扩展正则使用了分组符号"( )",(com|net)表示括号内的内容看出一个整体,而括号里的com|net表示com或者net。所以(com|net)$就表示以com结尾的行或者以net结尾的行。

扩展正则表达式总结:

常用符号
.   表示任意单个字符。
*  表示前面的字符连续出现任意次,包括0次。
.* 表示任意长度的任意字符,与通配符中的*的意思相同。
  表示转义符,当与正则表达式中的符号结合时表示符号本身。
| 表示"或者"之意
[  ]表示匹配指定范围内的任意单个字符。
[^  ]表示匹配指定范围外的任意单个字符。
 
单个字符匹配相关
[[:alpha:]]  表示任意大小写字母。
[[:lower:]]  表示任意小写字母。
[[:upper:]]  表示任意大写字母。
[[:digit:]]  表示0到9之间的任意单个数字(包括0和9)。
[[:alnum:]]  表示任意数字或字母。
[[:space:]]  表示任意空白字符,包括"空格"、"tab键"等。
[[:punct:]]  表示任意标点符号。
[^[:alpha:]]  表示单个非字母字符。
[^[:lower:]]  表示单个非小写字母字符。
[^[:upper:]]  表示单个非大写字母字符。
[^[:digit:]]  表示单个非数字字符。
[^[:alnum:]]  表示单个非数字非字母字符。
[^[:space:]]  表示单个非空白字符。
[^[:punct:]]  表示单个非标点符号字符。
[0-9]与[[:digit:]]等效。
[a-z]与[[:lower:]]等效。
[A-Z]与[[:upper:]]等效。
[a-zA-Z]与[[:alpha:]]等效。
[a-zA-Z0-9]与[[:alnum:]]等效。
[^0-9]与[^[:digit:]]等效。
[^a-z]与[^[:lower:]]等效。
[^A-Z]与[^[:upper:]]等效
[^a-zA-Z]与[^[:alpha:]]等效
[^a-zA-Z0-9]与[^[:alnum:]]等效
 
次数匹配相关
?  表示匹配其前面的字符0或1次
+  表示匹配其前面的字符至少1次,或者连续多次,连续次数上不封顶。
{n} 表示前面的字符连续出现n次,将会被匹配到。
{x,y} 表示之前的字符至少连续出现x次,最多连续出现y次,都能被匹配到,换句话说,只要之前的字符连续出现的次数在x与y之间,即可被匹配到。
{,n} 表示之前的字符连续出现至多n次,最少0次,都会陪匹配到。
{n,}表示之前的字符连续出现至少n次,才会被匹配到。
 
位置边界匹配相关
^:表示锚定行首,此字符后面的任意内容必须出现在行首,才能匹配。
$:表示锚定行尾,此字符前面的任意内容必须出现在行尾,才能匹配。
^$:表示匹配空行,这里所描述的空行表示"回车",而"空格"或"tab"等都不能算作此处所描述的空行。
^abc$:表示abc独占一行时,会被匹配到。
<或者 :匹配单词边界,表示锚定词首,其后面的字符必须作为单词首部出现。
>或者 :匹配单词边界,表示锚定词尾,其前面的字符必须作为单词尾部出现。
B:匹配非单词边界,与正好相反。
 
分组与后向引用
( ) 表示分组,我们可以将其中的内容当做一个整体,分组可以嵌套。
(ab) 表示将ab当做一个整体去处理。
1 表示引用整个表达式中第1个分组中的正则匹配到的结果。
2 表示引用整个表达式中第2个分组中的正则匹配到的结果。
原文地址:https://www.cnblogs.com/jkin/p/11913226.html