第四章 正则表达式
什么是正则表达式
在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具口换句话说,正则表达式就是记录文本规则的代码。
正则表达式的广泛应用
正则表达式在unix/linux系统中得到广泛的应用,强化了工具本身的功能。常见的UNIX下支持正则表达式的工具有:
》用于匹配文本行的grep工具族:
》用于改变输入流的sed流编辑器(streamediter);
》用于处理字符串的语言,如awk, python,perl, tcl等语言;
》文件查看程序,或分页程序,如mare. page, less等。
》文本编辑器,如ed, vi,emacs, vim等·
如何学习正则表达式
实例一
匹配当前存在 file单词并且在这个单词后还有一个file的句子
\bfile\b.*\bfile\b
Copy一段
假如你要找的是hi后面不远处跟着一个Lucy,你应该用\bhi\b.*\bLucy\b。
这里,.是另一个元字符,匹配除了换行符以外的任意字符。*同样是元字符,不过它代表的不是字符,也不是位置,而是数量——它指定*前边的内容可以连续重复使用任意次以使整个表达式得到匹配。因此,.*连在一起就意味着任意数量的不包含换行的字符。现在\bhi\b.*\bLucy\b的意思就很明显了:先是一个单词hi,然后是任意个任意字符(但不能是换行),最后是Lucy这个单词。
换行符就是'\n',ASCII编码为10(十六进制0x0A)的字符。
如果同时使用其它元字符,我们就能构造出功能更强大的正则表达式。比如下面这个例子:
0\d\d-\d\d\d\d\d\d\d\d匹配这样的字符串:以0开头,然后是两个数字,然后是一个连字号“-”,最后是8个数字(也就是中国的电话号码。当然,这个例子只能匹配区号为3位的情形)。
这里的\d是个新的元字符,匹配一位数字(0,或1,或2,或……)。-不是元字符,只匹配它本身——连字符(或者减号,或者中横线,或者随你怎么称呼它)。
为了避免那么多烦人的重复,我们也可以这样写这个表达式:0\d{2}-\d{8}。这里\d后面的{2}({8})的意思是前面\d必须连续重复匹配2次(8次)。
如果需要更精确的说法,\b匹配这样的位置:它的前一个字符和后一个字符不全是(一个是,一个不是或不存在)\w。
如何实践正则表达式
我们不是机器,总会犯错误。一般情况下,正则表达式不可能一次写正确。这就需要我们不断修改正则表达式,不断通近那个正确的写法,直到恰好达到我们想要的目的。
NOTE
历史上曾经出现过3种grep,可以用于匹配文本。它们是:
Grep 最早的文本匹配程序。使用PQSIX支持的基本正则表达式(Basic Regular Expression, BRE )
Egrep 扩展的grep(Extend grep)。使用扩展正则表达式〔Extended Regular Expression, ERE )
Fgrep 快速grep( Fast grep)。这个版本用于匹配固定字符串而不是正则表达式。
在I942年发布的PDS1X标准中,3个prep版本合而为一,POSIX可以通过参数来支持多个正则表达式模式,无论是BRE还是ERE,fgrep和egrep还是可以在所有的unix/inux系统上使用,但是被标记为deprecated(不推荐〕
正则基础
元字符
正则表达式是描述某种匹配规则的工具。
正则中有两种字符一种基本字符(没有任何意义),一种元字符(赋予了表达匹配的某些含义)
POSIXBRE和ERE都支持的meta字符
^
|
BRE,ERE
|
锚定行或者字符串的开始,如"^grep" 匹配所有以grep开头的行。
BRE:仅在正则表达式结尾处具有特殊含义;
ERE:在正则表达式的任何地方都有特殊含义。
|
$
|
BRE,ERE
|
锚定行或者字符串的结束,如"grep$" 匹配所有以grep结束的行。
BRE:仅在正则表达式结尾处具有特殊含义;
ERE:在正则表达式的任何地方都有特殊含义。
|
.
|
BRE,ERE
|
匹配一个非换行的任何单个字符(除NUL)。
如:‘gr.p'匹配gr后加一个任意字符后,然后p
|
*
|
BRE,ERE
|
匹配其前的任何数目或没有的单个字符,
例: . 表示任一字符, 则 .* 匹配任一字符的任意长度
|
[]
|
BRE,ERE
|
匹配方括号内的任一字符,其中可用连字符(-)指的连续字符的范围
;^符号苦出现在方括号的第一个位置,则表示匹配不在列表中的任一字符,
|
POSIXBRE中才有的字符:
\{n,m\}
|
区间表达式,匹配在它前面的单个字符重现的次数区别。
\{n\}指重现n次;\{n,m\}指重现n至m次;
|
\( \)
|
保留空间,可以将最多9个独立的子模式存储在单个模式中。
如\(ab\).*\1 : 指匹配ab组合的两次重现,中间可存在任意数目的字符。
|
\n
|
重复在\(与\)方括号内第n个子模式至此点的模式。
|
POSIXERE中才有的字符:
{n,m}
|
与BRE的\{n,m\}功能相同
|
+
|
匹配前面正则表达式的一个或多个扩展
|
?
|
匹配前面正则表达式的零个或一个扩展
|
|
|
匹配|符号前或后的正则表达式
|
( )
|
匹配方括号括起来的正则表达式群
|
Grep程序支持的meta字符plus
\<
|
锚定单词的开始,如:“\<grep” 匹配以grep开头的单词的行
|
\>
|
锚定单词的结束,
如:“grep\>”匹配包含以grep结尾的单词的行
|
\w
|
匹配文字和数字字符.也就是[A-Za-z0-9],
如’G\w*p‘匹配以G后跟零个或多个文字或数字字符.然后是p
|
\W
|
\w的反之形式,匹配一个或多个非单词字符,如点号、句号等
|
\b
|
单词锁定符,如:\bgrep\b只匹配grep
|
实例
//只显示以a开头的文件
[houchangren@ebsdi-23260-oozie shell]$ ls |grep '^a'
add.sh
a.sh
//显示a开头的文件中包含hadoop的行
[houchangren@ebsdi-23260-oozie shell]$grep 'hadoop' a*
a.sh:HADOOP_IN_PATH="/usr/lib/hadoop/bin/hadoop"
a.sh:HADOOP=$HADOOP_HOME/bin/hadoop
//显示a.sh文件中包含hadoop的行
[houchangren@ebsdi-23260-oozie shell]$grep 'hadoop' a.sh
HADOOP_IN_PATH="/usr/lib/hadoop/bin/hadoop"
HADOOP=$HADOOP_HOME/bin/hadoop
//显示连续五个a-z的字符在一行的行
[houchangren@ebsdi-23260-oozie shell]$ grep'[a-z]\{5\}' a.sh
HADOOP_IN_PATH="/usr/lib/hadoop/bin/hadoop"
HADOOP_DIR=`dirname "$HADOOP_IN_PATH"`/..
HADOOP=$HADOOP_HOME/bin/hadoop
HADOOP_VERSION=$($HADOOP version | awk '{if(NR == 1) {print $2;}}');
//显示如果test被匹配,es就被存储到内存中,并标记为1.然后搜索任意个字符(.*),这些字符后面跟着另外一个es (\1),找到就显示该行。\1是取占位括号中的值。
[houchangren@ebsdi-23260-oozie shell]$ cata.txt
I'm test; test;
so you don't worry!
[houchangren@ebsdi-23260-oozie shell]$ grep't\(es\)t.*\1' a.txt
I'm test; test;
为了在不同国家的字符编码中保持一至,POSIX(The PortableOperating System Interface)增加了特殊的字符类,如[:alnum:]是A-Za-z0-9的另·个写法。要把它们放到[]号内才能成为正则表达式,如[A-Za-z0-9]或[[:alnum: ]] 在Linux下的grep除fgrap外,都支持POSIX的字符类。方括号表达式除了上面提到的字符外,还支持其他的组成形式:
1. posix字符集
[:alnum:]
|
文字数字字符
|
[:alpha:]
|
文字字符
|
[:blank:]
|
空格与定位字符
|
[:cntrl:]
|
控制字符
|
[:digit:]
|
数字字符
|
[:graph:]
|
非空格字符
|
[:lower:]
|
小写字母字符
|
[:print:]
|
可显示的字符
|
[:punct:]
|
标点符号字符
|
[:space:]
|
空格字符
|
[:upper:]
|
大写字母字符
|
[:xdigit:]
|
16进制数字
|
2.排序符号
指将多个字符视为一个符号,如[.cn.]即将cn视为一个符号
3. 等价字符集
认为多个字符相等,如[=e=]在法文的locale里,可匹配于多种与e相似的字符
正则表达式允许将POSIX字符集与其他字符集混用。如[[:alpha:]!]匹配任意一个英文字母或者感叹号(!)。
//匹配或者数字或者!
[houchangren@ebsdi-23260-oozie shell]$ grep -E'[[:digit:]!]+' a.txt
so you don't worry!
单个字符
匹配单个字符的方式有4种:一般字符、转义的meta字符、.(点号)meta字符,和方括号表达式。
1.一般字符
例如:abc 就是 匹配abc
2.转义的meta字符
例如:\*匹配 * \[\] 匹配[]
3..(点号)字符
例如: .bc 匹配 abc,dbc等等
4.方括号表达式
例如:[cC]hina 只匹配 china 和Chnia
[^abc]d 匹配除了abc之外的任何小写字母
单个表达式匹配多个字符
文本的匹配锚点
^ 和& 开头和结尾的表示
运算符优先级
BRE的运算优先
运算符
|
含义
|
[..][==][::]
|
方括号符号
|
\meta
|
转义的meta字符
|
[]
|
方括号表达式
|
\(\)\n
|
后向引用表达式
|
*\{\}
|
区间表达式和星号表达式
|
无符号
|
连续
|
^&
|
锚点
|
ERE的运算优先
运算符
|
含义
|
[..][==][::]
|
方括号符号
|
\meta
|
转义的meta字符
|
[]
|
方括号表达式
|
()
|
分组
|
*+?{}
|
重置前置的正则表达式
|
无符号
|
连续
|
^&
|
锚点
|
|
|
交替
|
更多差异
1.向后引用
BRE中提供了一种机制名为“后向引用”backreferences,含义是:匹配的是之前正则表达式选定的部分。我们使用\1一\19来引用之前选定的模式,使用\(和\)括起想要之后引用的部分。
例如:
\(go\).*\1匹配一行中前后出现两个go
2.交替
交替是ERE才一有的特性。当使用方括号表达式时,表示可以“匹配这个字符,或者那个字符”,但是无法“匹配这个字符序列或那个字符序列”。当我们需要这个功能时,在ERE中,就用到交替.交替是在不同序列之间用管道符号隔开。例如,you|me匹配you或者me.
交替字符可以和管道符号一样,在一个正则表达式中使用多个来提供多种选择。因为交替字符的优先级最低,所以会一直扩展到新的交替字符,或正则表达式结束为止。
3.分组
在BRE中,我们使用一些meta字符修饰前置字符,匹配重复的情况。但是这样的操作仅仅
针对单个字符。在ERE中,分组功能能够计meta字符修饰前置字符串。分组符号就是使用(和)
将式子括起来。例如〔go)+匹配一个或多个连续的go.
在使用交替时,分组就非常有用。例如:(Lily|Lucy) will visit my house today.在这个正则表达式中,分组限定了访问我家的是Lily或者是Lucy。
正则表达式的应用
正则表达式之所以如此重要,一个原因是许多程序(包括UNIX/linux下的,和Win下的)
都使用正则表达式为自己提供扩展,以支持更强大的功能。
正则表达式的风格有两种,BRE和ERE,这是历史遗留的产物。egrep风格的正则表达式在
UNIX开发的早期就已经出现,但是Linux的创始人KenThompson觉得不需要在ed编辑器中使
用这样全方位的正则表达式支持,ed的标准后来演化为BRE。
ed又成为grep和sed的基础,故此。grep和sed支持的正则表达式类型是BRE。在pre-V7
时期,egrep被发明出来,egrep是使用的ERE风格正则。但是,当egrep, grep, fgrep合并成
个grep程序时,grep就同时支持不同风格的正则表达式〔通过一E选项支持ERE)o与此同时,egrep
虽然被从POSIX标准中踢出,但是许多UNIX/LINUX发行版本仍然文持egrep命令,而且许多历
史遗留脚本仍然在使用egrep,虽然标准做法应该是grep -E
使用ERE风格n则表达式的部分程序有egrep, awk和lex. lex是一个词法分析器构建程序,
除了特殊情况下,很少在shell编程中用到。
扩展
除了前面提到的BRE和ERE这两种标准正则表达式支持外,许多程序根据需求提供正则表
达式的语法扩展。最常见的扩展是\<和\>,分别匹配单词开头和单词结尾。
单词的开头有两种情况,一种是位于行的起始位置,一种是紧跟在非一单词组成字符后面;同样,单词的结尾也是两种情况;行的末尾和尾随一个非单词组成字符。
GUN支持额外的正则表达式运算符
|
含义
|
\w
|
匹配任何单词组成字符,等同[[:alnum:]]
|
\W
|
匹配任何非单组成字符,等同[^[:alnum:]]
|
\<\>
|
匹配单词的开头和结尾
|
\b
|
匹配单词开头和结尾处所找到的空字符o \bword就等同\<word\>
|
\B
|
匹配两个单词组成字符间的空字符串
|
\’\`
|
分别匹配emacs缓冲区的开头和结尾。GNU程序通常将它们视为与^和S同义
|
研究罗马数字
有点脑袋大,那天有心情在研究吧。
解析电话号码实例
echo '80055512121234' | grep -E"^[[:digit:]]{3}[^[:digit:]]*[[:digit:]]{3}[^[:digit:]]*[[:digit:]]{4}[^[:digit:]]*[[:digit:]]*$"
echo '800-555-1212' | grep -E"^[[:digit:]]{3}[^[:digit:]]*[[:digit:]]{3}[^[:digit:]]*[[:digit:]]{4}[^[:digit:]]*[[:digit:]]*$"
echo '800-555-1212-1234' | grep -E"^[[:digit:]]{3}[^[:digit:]]*[[:digit:]]{3}[^[:digit:]]*[[:digit:]]{4}[^[:digit:]]*[[:digit:]]*$"
echo 'work 1-(800) 555.1212 #1234' | grep-E "[[:digit:]]{3}[^[:digit:]]*[[:digit:]]{3}[^[:digit:]]*[[:digit:]]{4}[^[:digit:]]*[[:digit:]]*$"
表达式解析一下:
[[:digit:]]{3} 三位数字
[^[:digit:]]* 非数字的任何东西(或者没有)
[[:digit:]]{3} 三位数字
[^[:digit:]]* 非数字的任何东西(或者没有)
[[:digit:]]{4} 四位数字
[^[:digit:]]* 非数字的任何东西(或者没有)
[[:digit:]]* 数字(可没有)
分享到:
相关推荐
shell编程 正则表达式
运维看家本领之一:Shell脚本编程与正则表达式,运维看家本领之一:Shell脚本编程与正则表达式
一张图了解初步正则表达式,适合小白,通俗易懂,结构清晰
linux系统shell正则表达式-练习工具和教材 正则表达式-练习工具和教材 正则表达式-练习工具和教材
该讲义主要是用于Linux下shell编程。适合Linux初学者,用来学习正则表达式的基础。包含基础正则表达式和实例。
详细介绍了 shell编程 之 正则表达式,附有详细截图。
正则表达式之道,很不错的一个文档从网上拉下来的,能帮你快速的学会正则表达式。
Shell与Python正则表达式参考 正则表达式(RE)是一些由字符和特殊符号组成的字符串,它们描述了这些字符和字符的某种重复方式,因此能按某种模式匹配一个有相似特征的字符串的集合,简单地说,正则表达式就是用在字符...
Linux运维-3.Shell编程-12 shell编程-126正则实例.avi
这个是在培训机构学习的时候老师给的,上传来和大家分享下
Linux运维-运维系统服务04-Shell脚本d6-Shell函数与正则表达式-07case应用案例1.mp4
Linux运维-运维系统服务04-Shell脚本d6-Shell函数与正则表达式-13综合案例需求说明.mp4
Linux运维-运维系统服务04-Shell脚本d6-Shell函数与正则表达式-17综合案例实现3.mp4
Linux运维-运维系统服务04-Shell脚本d6-Shell函数与正则表达式-06case脚本中菜单打
我们可以在几乎所有的基于UNIX系统的工具中找到正则表达式的身影,例如,vi编辑器,Perl或PHP脚本语言,以及awk或sed shell程序等。此外,象JavaScript这种客户端的脚本语言也提供了对正则表达式的支持。由此可见,...
Linux运维-运维系统服务04-Shell脚本d6-Shell函数与正则表达式-10函数中return作用1.mp4
Linux运维-运维系统服务04-Shell脚本d6-Shell函数与正则表达式-05case语句基本语法结构
Linux运维-运维系统服务04-Shell脚本d6-Shell函数与正则表达式-04case语句基本语法结构