1.正则表达式概述

正则表达式又称正规表示式、正规表示法、正规表达式、规则表达式、常规表示法(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。

许多程序设计语言都支持利用正则表达式进行字符串操作。正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。正则表达式通常缩写成“regex”,单数有regexp、regex,复数有regexps、regexes、regexen。


2.基本语法

    一个正则表达式通常被称为一个模式(pattern),为用来描述或者匹配一系列符合某个句法规则的字符串。例如:Handel、Hndel和Haendel这三个字符串,都可以由“H(a||ae)ndel”这个模式来描述。大部分正则表达式的形式都有如下的结构:

选择

竖直分隔符代表选择。例如“gray|grey”可以匹配grey或gray。

数量限定

某个字符后的数量限定符用来限定前面这个字符允许出现的个数。最常见的数量限定符包括“+”、“?”和“*”(不加数量限定则代表出现一次且仅出现一次):

加号代表前面的字符必须至少出现一次。(1次、或多次)。例如,“goo+gle”可以匹配google、gooogle、goooogle等;

问号代表前面的字符最多只可以出现一次。(0次、或1次)。例如,“colou?r”可以匹配color或者colour;

星号代表前面的字符可以不出现,也可以出现一次或者多次。(0次、或1次、或多次)。例如,“0*42”可以匹配42、042、0042、00042等。

匹配

圆括号可以用来定义操作符的范围和优先度。例如,“gr(a|e)y”等价于“gray|grey”,“(grand)?father”匹配father和grandfather。

上述这些构造子都可以自由组合,因此,“H(ae?|)ndel”和“H(a|ae|)ndel”是相同的。

精确的语法可能因不同的工具或程序而异。

 

3.正则表达式基础

基本概念

字符串组成

对于字符串“a5”,是由两个字符“a”、“5”以及三个位置组成的,这一点对于正则表达式的匹配原理理解很重要。

​            

正则表达式(grep,egrep,fgrep)_字符串

占有字符和零宽度

正则表达式匹配过程中,如果子表达式匹配到的是字符内容,而非位置,并被保存到最终的匹配结果中,那么就认为这个子表达式是占有字符的;如果子表达式匹配的仅仅是位置,或者匹配的内容并不保存到最终的匹配结果中,那么就认为这个子表达式是零宽度的。

占有字符还是零宽度,是针对匹配的内容是否保存到最终的匹配结果中而言的。

占有字符是互斥的,零宽度是非互斥的。也就是一个字符,同一时间只能由一个子表达式匹配,而一个位置,却可以同时由多个零宽度的子表达式匹配。

由一类字符书写的模式,其中有些字符不表示字符字面意义,而是表达控制或通配的功能。

 

正则表达式构成

正则表达式由两种字符构成。一种是在正则表达式中具体特殊意义的“元字符”,另一种是普通的“文本字符”。

元字符可以是一个字符,如“^”,也可以是一个字符序列,如“\w”。

我们建立一个文件来说明元字符。

#cat test.txt​​       

​​ab​​

​​cb​​

​​abx​​

​​aaaaaab​​

​​aaaaaaaaaaaaaab​​


                                    

 

元字符(Meta Character)

1.[…] 字符组(CharacterClasses)

字符组可以匹配[ ]中包含的任意一个字符。虽然可以是任意一个,但只能是一个。

字符组支持由连字符“-”来表示一个范围。当“-”前后构成范围时,要求前面字符的码位小于后面字符的码位。

…] 排除型字符组。排除型字符组表示任意一个未列出的字符,同样只能是一个。排除型字符组同样支持由连字符“-”来表示一个范围。

字符匹配:字符通配

.:匹配任意单个字符。

         ​

正则表达式(grep,egrep,fgrep)_字符串_02

:匹配指定集合中的任意单个字符。

         ​

正则表达式(grep,egrep,fgrep)_锚定_03

:匹配指定集合外的任意单个字符

         ​

正则表达式(grep,egrep,fgrep)_字符串_04

        

量词(Quantifier)

 量词表示一个子表达式可以匹配的次数。量词可以用来修饰一个字符、字符组,或是用()括起来的子表达式。一些常用的量词被定义成独立的元字符。

:表达式匹配前面任意次,0,1或者多次,前面字符出现与否都匹配,相当于{0,}。

         ​

正则表达式(grep,egrep,fgrep)_正则表达式_05

 

:表达式匹配1次或意多次,至少1次,相当于{1,}

     ​

正则表达式(grep,egrep,fgrep)_字符串_06

 

:表达式匹配0次或1次,相当于{0,1}

     ​

正则表达式(grep,egrep,fgrep)_字符串_07

 

:表达式匹配其前面的字符m次

     ​

正则表达式(grep,egrep,fgrep)_正则表达式_08

 

:表达式匹配最少m次,最多n次

     ​

正则表达式(grep,egrep,fgrep)_锚定_09

注意:在不是动态生成的正则表达式中,不要出现“{1}”这样的量词,如“\w{1}”在结果上等价于“\w”,但是会降低匹配效率和可读性,属于画蛇添足的做法。

:匹配任意长度的任意字符

         ​

正则表达式(grep,egrep,fgrep)_锚定_10

 

位置锚定

:行首锚定,出现最左侧

         ​

正则表达式(grep,egrep,fgrep)_锚定_11

        

:行尾锚定,出现最右侧

         ​

正则表达式(grep,egrep,fgrep)_正则表达式_12

        

^$:表示空白行

         ​

正则表达式(grep,egrep,fgrep)_锚定_13

        

:词首锚定,在查找的单词模式的左侧;\<char

         ​

正则表达式(grep,egrep,fgrep)_字符串_14

        

:词尾锚定,在查找的单词模式的右侧;char\>

         ​

正则表达式(grep,egrep,fgrep)_字符串_15

:匹配单词

         ​

正则表达式(grep,egrep,fgrep)_正则表达式_16

 

4.捕获组(Capture Group)

捕获组就是把正则表达式中子表达式匹配的内容,保存到内存中以数字编号或手动命名的组里,以供后面引用。

:普通捕获组,将子表达式Expression匹配的内容保存到以数字编号的组里

:命名捕获组,将子表达式Expression匹配的内容保存到以name命名的组里

普通捕获组(在不产生歧义的情况下,简称捕获组)是以数字进行编号的,编号规则是以“(”从左到右出现的顺序,从1开始进行编号。通常情况下,编号为0的组表示整个表达式匹配的内容。

命名捕获组可以通过捕获组名,而不是序号对捕获内容进行引用,提供了更便捷的引用方式,不用关注捕获组的序号,也不用担心表达式部分变更会导致引用错误的捕获组。

 

非捕获组:一些表达式中,不得不使用( ),但又不需要保存( )中子表达式匹配的内容,这时可以用非捕获组来抵消使用( )带来的副作用。

:进行子表达式Expression的匹配,并将匹配内容保存到最终的整个表达式的区配结果中,但Expression匹配的内容不单独保存到一个组内

 

反向引用:捕获组匹配的内容,可以在正则表达式的外部程序中进行引用,也可以在表达式中进行引用,表达式中引用的方式就是反向引用。

反向引用通常用来查找重复的子串,或是限定某一子串成对出现。

,\2:对序号为1和2的捕获组的反向引用

:对命名为name的捕获组的反向引用

举例:

“(a|b)\1”在匹配“abaa”时,匹配成功,匹配到的结果是“aa”。“(a|b)”在尝试匹配时,虽然既可以匹配“a”,也可以匹配“b”,但是在进行反向引用时,对应()中匹配的内容已经是固定的了。

我们来实验一下:

# vi test3.txt​​       

​​aaaaaaaaaax​​

​​abbbbbbbbbx​​

​​abababababx​​

​​abbx​​

​​abx​​

​​abbbx​​


我们要限定只找限定ab出现1-3次的:

正则表达式(grep,egrep,fgrep)_正则表达式_17

​​# cat test2.txt​​       

​​acbhelloacb123​​

​​aabhiacb123​​

​​abaworldabb123​​

​​acbbadacb234​​

​​adbcloseadb234​​

​​adbcloseasb2345​​


我们要求找到以a开始中间跟任意字符,再以b结尾的行,这个行后面再一次出现同样条件的行。

下面的例子能实现匹配以a开头以b结尾,但是中间的字符不一致也匹配。

正则表达式(grep,egrep,fgrep)_正则表达式_18

我们使用分组的反向引用来实现:

正则表达式(grep,egrep,fgrep)_正则表达式_19


贪婪与懒惰

当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。以这个表达式为例:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。

有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。现在看看懒惰版的例子吧:

匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)。

懒惰限定符

重复任意次,但尽可能少重复

重复1次或更多次,但尽可能少重复

重复0次或1次,但尽可能少重复

重复n到m次,但尽可能少重复

重复n次以上,但尽可能少重复

5.grep,egrep,fgrep介绍

Unix的grep家族包括grep、egrep和fgrep。egrep和fgrep的命令只跟grep有很小不同。egrep是grep的扩展,支持更多的re元字符, fgrep就是fixed grep或fast grep,它们把所有的字母都看作单词,也就是说,正则表达式中的元字符表示回其自身的字面意义,不再特殊。linux使用GNU版本的grep。它功能更强,可以通过-G、-E、-F命令行选项来使用egrep和fgrep的功能

 

:Global searchRegular expression and Print out the line

:Extended Globalsearch Regular expression and Print out the line

:Fast Global searchRegular expression and Print out the line


Linux grep是基础的正则表达式,命令用于在文件内查找指定的字符串。

全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。

搜寻字符串' filename

选项与参数:

:将 binary 文件以 text 文件的方式搜寻数据

:计算找到 '搜寻字符串' 的次数

:忽略大小写的不同,所以大小写视为相同

:顺便输出行号

:反向选择,亦即显示出没有 '搜寻字符串' 内容的那一行!

:可以将找到的关键词部分加上颜色的显示喔!

-B :附带显示前面两行

-A :附带显示后面两行

-C :附带显示上下两行一起 

 

Linux egrep是扩展的正则表达式,命令用于在文件内查找指定的字符串。

执行效果与"grep-E"相似,使用的语法及参数可参照grep指令,与grep的不同点在于解读字符串的方法。

是用extendedregular expression语法来解读的,而grep则用basic regular expression 语法解读,extended regularexpression比basic regular expression的表达更规范。

 

扩展正则表达式的元字符:和基础的没啥区别,就是有些字符不需要\了。

 

字符匹配

:匹配任意单个字符

:指定集合中的任意单个字符

:匹配指定集合外的任意单个字符

匹配前面的字符出现至少1次

 

匹配次数限定

:匹配前面任意次,0,1或者多次,前面字符出现与否都匹配

:匹配其前面的字符0次或1次

:匹配其前面的字符m次

:匹配其前面的字符至少m次,至多n次,{m,} 表示至少m,至多不限制,{0,n}表示至少0次,至多n次

:匹配任意长度的任意字符

 

字符锚定

:行首锚定,出现最左侧

:行尾锚定,出现最右侧

:表示空白行

:词首锚定,在查找的单词模式的左侧;\<char

:词尾锚定,在查找的单词模式的右侧;char\>

:匹配单词

 

 和grep差不多

模式从左到右,引用第#个左括号以及与其匹配右括号之间的模式匹配到的内容,

\1 , \2

或者b,ab|cd就是ab或者cd。

 

Linux fgrep不使用正则表达式,查询速度比grep命令快,但是不够灵活:它只能找固定的文本,而不是规则表达式。

如果你想在一个文件或者输出中找到包含星号字符的行

​    

正则表达式(grep,egrep,fgrep)_字符串_20

​    

正则表达式(grep,egrep,fgrep)_锚定_21

个人觉得捕获组的概念有些困难,本文对egrep没有实例说明,但是可以根据上文中的grep的例子做实验对比,效果更好,不明白可以google一下。


本文并非所有都原创,有些概念摘自网上博文,下面贴出,以表谢意:

中文wiki:http://zh.wikipedia.org/wiki/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F