正则表达式(Regular Expression)是强大、便捷、高效的文本处理工具。
正则表达式的元字符与其他字符结合起来,实现我们期望的功能。
典型元字符:
^ 脱字符,一行的起始,匹配的是行开始的位置
$ 美元符,一行的结束,匹配的是行结尾的位置
| 竖线、管道,多选结构,匹配分隔两边的任意子表达式
(…) 括号,限制竖线(管道)的作用范围,单用grep不支持,需用grep -E或egrep
[…] 字符组,匹配里面的若干字符之一(正则表达式结构体Construct[],列出在某处期望匹配的字符)
[^…] 排除型字符组,匹配未列出的任意字符
- 连字符,表示一个范围,用于字符组内部时才是元字符
. 点号,单个任意字符,用来匹配任意字符的字符组的简便写法
\< 反斜线小于,单词分界符\<用于匹配单词(字符组合,字母数字符号)开头的位置
\> 反斜线大于,单词分界符\>用于匹配单词(字符组合,字母数字符号)结束的位置
同一字符在不同位置,含义可能不一样,需注意区分。加参数-i表示匹配时不区分大小写。
实例分析:
cat 寻找一行文本中任意位置的cat,如cat、catalog、scat、scatter
^cat 寻找行首的cat,如catalog
cat$ 寻找行尾的cat,如scat
^cat$ 只包含cat的行
^$ 空行,没有任何字符(包括空白字符)
^ 单独使用无意义
\<cat\> 匹配单词cat
^(From|Subject): 表示寻找以From:或者Subject:开头的行
包含型字符组:
[123456] 匹配1到6中的任意一个数字
<H[123456]> 匹配<H1>~<H6>,可以写成<H[1-6]>,-为连字符,用于字符组内部时,表示一个范围。
[0-9] 匹配一个数字
[a-z] 匹配一个小写字母
[A-Z] 匹配一个大写字母
[0-9A-Z_!.?] 匹配一个数字、大写字母、下划线、惊叹号、点或问号
[0123456789abcdefABCDEF] 可以写成[0-9a-fA-F]或者[A-Fa-f0-9],顺序无所谓,适合处理16进制数字
[abc]、[a-c]、(a|b|c)表示同一个意思,但不是所有字符都可以这样表示。字符组效率相对较高。
排除型字符组:
[^…] 匹配任何未列出的字符,字符组内部开头的^表示排除(negate),列出不希望匹配的字符
n[^d] 匹配n后面不是字符d的行
[^d] 匹配不是仅包含字母d的行,即排除仅包含字母d的行
排除型字符组表示“匹配未列出的字符(match a character that’s not listed)”,而不是“不要匹配列出的字符(don’t match what is listed)”。
匹配文件目录/路径的方法:
./([^/]+)/ 匹配./后面不是只有/但可以是其他字符(出现次数不限)的行,最后面还有/
实测发现此正则表达式还不够严谨
因为.是匹配单个任意字符(不一定是. 还可能是字母或其它字符)
若要匹配单独的. 需要加转义符\或者脱字符^
实例:[root@CentOS6 shell]# grep -E '\./([^/]+)/' dir.txt # 加转义符\
./home/
./...yes../
./new/
./100/
./中国/
./2015/
./2014-12-31/
[root@CentOS6 shell]# grep -E '^./([^/]+)/$' dir.txt #加行首行尾锚定符^和$
./home/
./...yes../
./new/
./100/
./中国/
./2015/
./2014-12-31/
[root@CentOS6 shell]# cat dir.txt
//
.//
./home/
./...yes../
.//~/
./new/
./100/
./中国/
./2015/
./2014-12-31/
/hometown/
yesterday
@China
.///
.
.//~/~/
abcd//~/
..//../
[root@CentOS6 shell]#用点号.匹配任意字符:
元字符.(也称点号dot、小点point)是用来匹配任意字符的字符组的简便写法。
如果需要在表达式中使用一个“匹配任意字符”的占位符(placeholder),用点号.就很方便。
例如:
要搜索03/19/76、03-19-76、03-19-76,表达式可以写成字符组形式:03[-./]19[-./]76
也可以使用点号.替代字符组:03.19.76
相对而言,03[-./]19[-./]76更精确,03.19.76里的点号.匹配到还可能是其他字符。具体用哪个取决于目标文本的情况。
字符组内的点号.不是元字符,仅代表普通的点字符;
在字符组内的连字符-,是否表示范围要看其所在位置,在开头或结尾都不是表示范围,在中间(且不是在[^后面)的才是。例如:[.-/]中-是表示范围,但[^-/.]、[./-]里的-都不是表示范围。
管道|多选结构:匹配任意子表达式
|也是一个元字符,意为或(or),通过它可以把不同的子表达式组合成一个总的表达式,在这样的组合中,子表达式称为“多选分支(alternative)”。
如:gr[ea]y 可以采用|写成grey|gray,或者gr(a|e)y。
注意不要写成gr[a|e]y,这里面的|只是普通的字符,因为在字符组内部。
多选结构可以包括很多字符,但不能超越括号的界限。
一个字符组只能匹配目标文本中的单个字符,而每个多选结构自身都可能是完整的正则表达式,都可以匹配任意长度的文本。
(first|1st)与(fir|1)st 同一意思
(First|1st) [Ss]treet与(Fir|1)st [Ss]treet 同一意思
在一个包含多选结构的表达式中使用脱字符^和美元符$的时候要小心。
分析:
^From|Subject|Date: 匹配^From或Subject或Date:
^(From|Subject|Date): 匹配^From:或^Subjec:或^Date: 常用于提取E-mail文件中的信息
两者的匹配结果是不一样的。
如果希望在每个多选分支之前都有脱字符^,之后都有:,需要使用括号来限制(constrain)这些多选分支。
典型用法:
grep -E 'From:|Subject:' test.txt
grep -E '^(From|Subject|Date):' test.txt //单引号、双引号都可以,扩展正则
egrep '^(From|Subject|Date):' test.txt
元字符序列\<和\> 单词分界符:
使用正则表达式时经常会遇到一个问题,就是期望匹配的“单词”包含在另一个单词之中。
单词分界符\<和\>用于匹配单词开头和结束的位置。注意:<和>本身并不是元字符,只有当它们与斜线\结合起来的时候,整个序列才有特殊意义(称为元字符序列)。不是所有的egrep版本都支持单词分界符。
分析:
\<cat\>意为匹配单词的开头位置,然后是c a t这3个字母,之后是单词的结束位置,简单的说就是匹配cat这个单词。
也可以用\<cat和cat\>来分别匹配以单词(或者说字母组合)cat开头和结束的单词。
egrep(相当于grep -E)认定的单词开头位置用向上的箭头标识,单词结束位置用向下的箭头标识。
“单词的开始和结束”准确地说是“字母数字字符号的开始和结束”。
可选项元素、通配符Wildcards:
optional items可选项元素
问号? 代表可选项,表示任意单个字符,把它加在一个字符的后面,就表示此处容许出现这个字符,不过它的出现并非匹配成功的必要条件。哪个字符可选,?就放在哪个字符后面。需要使用egrep或grep -E。
color、colour 可以通过colou?r来匹配
July、Jul 可以通过July?或(July|Jul)来匹配
fourth|4th|4 可以通过fourth|4(th)?来匹配 嵌套了括号,问号?作用的对象是整个括号内的内容。
括号及反向引用
括号的用途:
1、限制多选项的范围
2、将若干字符组合为一个单元,受问号?或星号*之类量词的作用,如four(th)?、(a)*
3、反向引用backreference 容许匹配与表达式先前部分匹配的同样的文本
例如:\<([A-Za-z]+).+\1\> 这里的括号()和\1用于支持反向引用
在支持反向引用的工具软件中,括号()能够“记忆”其中的子表达式匹配的文本,不论这些文本是什么,元字符序列\1都能记住它们。而且,在一个表达式中可以使用多个括号,在用\1、\2、\3等来表示第一、第二、第三组括号匹配的文本。括号是按照开括号“(”从左至右的出现顺序进行的。
例如:([a-z])([0-9])\1\2中的\1代表[a-z]匹配的内容,\2代表[0-9]匹配的内容。
转义
.本身是元字符,它可以匹配任何字符,包括空格。
真正匹配文本中点号.的元序列应该是反斜线(backslash)加上点号的组合:
aga\.att\.com
\.称为“转义的点号”或“转义的句号”,这种方法适用于所有的元字符,但在字符组内部无效。
这样使用的反斜线成为“转义符(escape)”——它作用的元字符会失去特殊含义,成为普通字符。
还可以用\([a-zA-Z]+\)来匹配一个括号内的单词,例如(very),在开闭括号之前的反斜线消除了开闭括号的特殊意义,于是能够匹配文本中的开闭括号。
许多程序设计语言都有标识符(identifier,例如变量名)的概念。
标识符只包含字母、数字以及下划线,但不能以数字开头。
可以用[a-zA-Z_][a-zA-Z_0-9]*来匹配标识符:
第一个字符组匹配可能出现的第一个字符;
第二个(包括对应的*)匹配余下的字符。
引号内的字符串:
匹配引号内的字符串,最简单的方法是使用表达式:”[^”]*”
两端的引号用来匹配字符串开头和结尾的引号。
在这两个引号之间的文本可以包括双引号之外的任何字符。
这里用[^”]来匹配除双引号”之外的任何字符,用*来表示两个引号之间可以存在任意数目的非双引号字符。
美元金额(可能包含小数):
\$[0-9]+(\.[0-9][0-9])?是一种匹配美元金额的办法。
三个部分:\$、…+、(…)?
分别匹配一个美元符号、小数点前的数字(一个或一组数字)、小数点及其之后的数字(一个小数点和两位数字),可以匹配$100.1之类的美元金额,但不能匹配$1,100这样的金额,小数部分是可选的。
如果要匹配的是只包含价格而不含其他字符的行,可以在此表达式两端加上^…$,即:
^\$[0-9]+(\.[0-9][0-9])?$ 开头为美元符$,结尾为数字,且必须包含小数点,匹配结果与前者不同
这个表达式不能匹配$.49。
因为:
^ 脱字符,一行的起始,匹配的是行开始的位置
$ 美元符,一行的结束,匹配的是行结尾的位置
网址HTTP/HTML URL:
网址(Web URL)的形式可能有很多种,所以构造一个能够匹配所以形式的URL的正则表达式很有难度。
但如果只要求匹配大多数常见的URL,则相对比较简单。
常见的HTTP/HTML URL样式如下:
http://hostname/path.html(或htm)
主机名(hostname)(如www.yahoo.com)的规则比较复杂,但因为主机名一般跟在http://之后,可以写成:
[-a-z0-9_.]+ (可能应该是[-a-z0-9_.:]+)
path部分的变换更多,需要写成:
[-a-z0-9_:@&?=+,.!/~*%$]*
注意:用作普通字符的连字符-必须放在字符组的开头,用在字符组中间的是表示范围的元字符。
综合起来就是:
egrep -i ‘\<http://[-a-z0-9_.:]+/[-a-z0-9_:@&?=+,.!/~*%$]*\.html?\>' files
更简化的版本:
egrep -i ‘\<http://[^ ]*\.html?\>' files
可能匹配出一些错误结果,根据具体需求调整表达式即可。
参考:
1、《[精通正则表达式(第三版)].(美)佛瑞德.扫描版.pdf》
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/29734436/viewspace-2141300/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/29734436/viewspace-2141300/