zoukankan      html  css  js  c++  java
  • 正则表达式详解

    正则表达式详解

    正则表达式,又称规则表达式。(英语: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个分组中的正则匹配到的结果。
    
  • 相关阅读:
    bzoj 2730: [HNOI2012]矿场搭建
    bzoj 1179: [Apio2009]Atm
    strcpy,strlen, strcat, strcmp函数,strlen函数和sizeof的区别
    C语言printf的格式
    C语言中交换两个数值的方法
    C语言中 指针的基础知识总结, 指针数组的理解
    自定义方法实现strcpy,strlen, strcat, strcmp函数,了解及实现原理
    选择排序
    冒泡排序的优化
    storyBoard中取消键盘第一响应
  • 原文地址:https://www.cnblogs.com/jkin/p/11913226.html
Copyright © 2011-2022 走看看