正则表达式详解
正则表达式,又称规则表达式。(英语: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个分组中的正则匹配到的结果。