本文共 10933 字,大约阅读时间需要 36 分钟。
了解正则表达式语法:
正则表达式(regular expression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。
\列出目录时,dir *.txt 或 ls *.txt 中的 *.txt 就不是一个正则表达式,因为这里 * 与正则式的 * 的含义是不同的。
\构造正则表达式的方法和创建数学表达式的方法一样。也就是用多种元字符与运算符可以将小的表达式结合在一起来创建更大的表达式。正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。
正则表达式是由普通字符(例如字符 a 到 z)以及特殊字符(称为"元字符")组成的文字模式。模式描述在搜索文本时要匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
普通字符
普通字符包括没有显式指定为元字符的所有可打印和不可打印字符。这包括所有大写和小写字母、所有数字、所有标点符号和一些其他符号。
元字符汇总
. 匹配除换行符以外的任意单个字符。在awk中,句点也能匹配换行符。
* 匹配任意一个(包括零个)在它面前的字符,(包括由正则表达式指定的字符)
[...]匹配方括号中的字符类的任意一个。如果方括号中第一个字符为脱节字符(^),则表示否定匹配,即匹配除了换行符和类中列出的那些字符以外的所有字符,在awk中也匹配换行符。连字符(-)用于表示字符的范围。如果类中的第一个字符为右方括号(]),则表示它是类的成员。所有其他的元字符在被指定为类中的成员时都会失去他们原来的意义。
^ 如果作为正则表达式中的第一个字符,则表示匹配行的开始。在awk中匹配字符串的开始,即使字符串包含嵌入的换行符。
$ 如果作为正则表达式中的最后一个字符,则表示匹配行的结束。在awk中匹配字符串的结尾,即使字符串包含嵌入的换行符。
\{n,m\}匹配它前面某个范围内单个字符出现的次数(包括由正则表达式指定的字符),\{n\}将匹配n次出现,\{n,\}至少匹配n次出现,而且\{n,m\}匹配n和m之间的任意次出现。
\ 转义随后的特殊字符
扩展的元字符(egrep和awk)
+匹配前面的正则表达式的一次或者多次出现。
?匹配前面的正则表达式的零次或者一次出现。
|指定可以匹配其前面的或者后面的的正则表达式。
()对正则表达式分组。
{n,m}匹配它前面某个范围内单个字符出现的次数,(包括由正则表达式指定的字符),{n}表示匹配n次出现,{n, }至少匹配n次出现,{n,m}匹配n和m之间的任意次出现。(用于POSIX的egrep和POSIX的awk,而不是传统的egrep和awk)。
普通存在的反斜杠 \
元字符反斜杠(\)将元字符转换为普通字符(和将普通字符转换为元字符),它强制将任意元字符解释为普通文字,以便匹配该字符本身。
它的用法:\( \) \{ \} \n
字符类中的特殊字符
\ 转义任意特殊字符(只用于awk中) 只在awk中式特殊的,因此可以使用字符类"[a\]1]"以匹配一个a、一个],或一个1。
-当它不在第一个或者最后一个位置时,表示一个范围
^仅当在第一个位置时表示翻转匹配
字符的范围
连字符用于指定一个字符范围,例如,所有大写字母的范围可以指定为:[A-Z]
一个数字的数字范围可以指定为:[0-9]
该字符类有助于解决匹配文章引用的问题。
例如:[cC]hapter [1-9]
它匹配字符串‘chapter’或者‘Chapter’且后面跟有空格,然后是从1到9的任意单个数字。
eg: you will find the information in chapter 9.
[0-9a-z?,.;:'"]这个表达式将匹配任意的单个字符,可以是数字,小写字母,问号,逗号,句点,分号,冒号,单引号,引号。记住每个字符类都匹配单个字符。
如果指定多个类,可以描述多个连续的字符。
[a-zA-Z][.?!]这个表达式匹配“任意后面跟有句点,问号,感叹号的小写或者大写的字面”
[-+*/]如果连字符在一个类中是第一个或者最后一个字符,则失去其特殊含义,为了匹配算是操作符,在下面的示例中将连字符(-)放在第一位。
用正在匹配日期的两种格式:
MM-DD-YY
MM/DD/YY
排除字符集
通常字符类包括在哪个位置想要匹配的所有字符。在类中作为第一个字符的脱字节(^)将类中的所有字符由排除再被匹配之外。相反,除换行符以外的的没有列在方括号中的任意字符都将匹配。
[^0-9] 将匹配任意非数字字符。它将匹配所有的大写和小写字母,以及所有特殊符号,例如,标点符号。
[^aeiou]排除元音,匹配任意的辅音,大写的任意元音,任意标点符号或者特殊字符。
举例如下的表达式:
\.DS "[^1]" 该表达式匹配字符串,“.DS”其后依次跟随一个空格、一个双引号、一个非数字和一个双引号。这样设置是为了避免匹配如下:.DS "1" ,而匹配这样的行: .DS "|" .DS "2"
POSIX字符类
类 匹配字符
[:alnum:] 可打印的字符(包括空白字符)
[:alpha:] 字母字符
[:blank:] 空格和制表符
[:cntrl:] 控制字符
[:digit:] 数字字符
[:graph:] 可打印的和可见的(非空格)字符
[:lower:] 小写字符
[:print:] 可打印的字符(包括空白字符)
[:punct:] 标点符号字符
[:space:] 空白字符
[:upper:] 大写字符
[:xdigit:] 十六进制数字
重复出现的字符
星号(*)元字符表示它前面的正则表达式可以出现零次或多次。也就是说,如果它修改了单个字符,那么该字符可以在那里也可以不在那里,并且如果它在那里,那可能会不止出现一个。可以使用星号元字符匹配出现在引号中的单词。
当星号用于修复字符类时,则可以匹配类中的任意数目的的字符。
cat summ.txt
i can do it i cannot do it i can not do it i can't do it i cant do it##############################
匹配以上语句的否定语句,但是不匹配肯定语句,可以使用如下的正则
grep "can[ no' ]*t" summ.txt
i cannot do it i can not do it i can't do it i cant do it元字符加号可以被认为是“至少一个”的前导字符,事实上,他和许多人使用的“*”号相对应。
问号(?)匹配零次或者一次出现。例如:
“80286”“80386”“80486”“80586”使用正则表达式匹配,如果我们还想匹配字符串“8086”,可以使用egrep或awk编写正则表达式。
80[2345]?86 :它匹配"80"后面跟的"一个2","一个3","一个4","一个5",或者没有字符,然后跟字符串“86”。
匹配单词,有时候匹配单词很难,例如:想匹配模式“book”,搜索会命中包含单词“book”“books”“bookish”"handbook"“booky”,如果遇到此类情况,则需要在"book"前后使用空格来限制匹配情况。
举例:
[root@localhost opt]# cat zhang.txt
Here are the books that you requested
Yes,it is a good book for children
it is amazing to think that it was called a "harmful book" when once you get to the end of the book,you can't believe
book.(.为空格的意思)
[root@localhost opt]# grep ' book ' zhang.txt
Yes,it is a good book for children但是此表达式只匹配单词“book”,它会丢掉匹配“books”,为了匹配单数或者复数单词,可能要使用星号元字符。
[root@localhost opt]# grep ' books* ' zhang.txt Here are the books that you requested Yes,it is a good book for children
. books.*这样可以匹配“book”或者“books”然而,如果单词后面有逗号,句点,问号或者引号时就不匹配“book”。
[root@localhost opt]# grep ' book.* ' zhang.txt Here are the books that you requested Yes,it is a good book for children it is amazing to think that it was called a "harmful book" when once you get to the end of the book,you can't believe
当星号和通配符(.)结合起来使用时,可以匹配任意字符的零次或者多次出现。
. book.* .这个表达式匹配字符串“book”,其后面跟有任意个字符或者没有字符,最后跟着空格。
. book.? .
定位元字符
有两个元字符用于指定字符串出现在行首或者行末的上下文。脱字符(^)元字符是指示开始的单字符正则表达式,美元符号($)元字符是指示行结尾的单字符正则表达式。这些通常被称为“定位符”,因为他们将匹配限定在特定的位置。
[root@localhost opt]# cat zhang.txt
Here are the books that you requested可以使用以下的表达式打印以制表符开始的行:
^.
eg:
[root@localhost opt]# grep -c '^.' zhang.txt
3
通常,使用vi输入要由troff处理的文本,并且不想让空格出现在行的结尾。如果想找到(并且删除他们),下面的正则表达式可以匹配在结尾处有一个或者多个的行。
()()*$[()表示的是空格]
[root@localhost opt]# grep -c ' *$' zhang.txt
0
匹配行首有一个句点,随后跟有两个字符的字符串,然后是一个空格的行。 ^\...()[()表示的是空格]
可以使用两个连续的定位元字符来匹配空行,例如:
[root@localhost opt]# grep -c '^$' zhang.txt
2
可以使用sed来删除空行,下面的正则表达式可用于匹配空行,即使其中包含空格:'^ *$'。 同样可使用此表达式匹配整个行: '^.*$'
[root@localhost opt]# grep -c '^ *$' zhang.txt
2
[root@localhost opt]# grep -c '^.*$' zhang.txt
5
字符的跨度
这个元字符指示了一个不确定的长度,这允许你指定重复出现的字符,现在我们来看一对用于指定跨度并决定跨度长度的元字符,可以指定一个字母字符或正则表达式出现的最小或者最大的次数。
在grep和sed中使用\{和\},POSIX egrep和 POSIX awk 使用{和}。在任意情况下大括号包围一个或者两个参数。
\{n,m\} :n和m是0到255之间的整数,如果只指定\{n\}本身,那么将精确匹配前面的字符或者或正则表达式的n次出现。如果指定\{n,m\},那么就匹配出现的次数为n和m之间的任意数。
注意:“?”等价于"\{0,1\}","*"等价于"\{0,\}" , "+"等价于"\{1,\}",没有等价于"\{1\}"的修饰符。
例如:下面的表达式将匹配“1001”、“10001”、“100001”但是不匹配“101”或者“1000001”
10\{2,4\}1
[0-9]\{3\}-[0-9]\{2\}-[0-9]\{4\} 3个数字,一个连字符,加两个数字一个连字符,四个数字
[0-9]\{3\}-[0-9]\{4\}三个数字,一个连字符,四个数字
如果使用POSIX之前的awk,大括号就不用写,只能简单的重复适当次数的字符类。
[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]
选择性操作
竖线(|)元字符是元字符扩展集的一部分,用于指定正则表达式的联合,如果某行匹配其中的一个正则表达式,那么它就匹配该模式。
例如:LINUX|UNIX将匹配包含字符串“Linux”或者“Unix”的行。也可以指定更多的选择,
LINUX|UNIX|EATANB 表示:使用egrep打印匹配这3种模式的任意一种的行。
sed中没有联合元字符,可以分别指定每种模式。
分组操作
园括号()用于对正则表达式进行分组并设置优先级,他们是元字符扩展集的一部分,假设在文本文件中将公司的名称为:“BigOne”或者是“BigOne Computer”,使用如下的正则表达式:
BigOne ( Computer)? #将匹配字符串"BigOne"本身或者后面跟有一个字符串“ Computer”的形式。同样,有些术语有时会有全拼,有时会用缩写,则可以使用如下:
[root@localhost opt]# egrep "Labo(ratorie)?s" mail.list
Bell Laboratories,Lucent Technologies Bell Labos可以使用竖线和圆括号来对选择性操作进行分组,可以用来指定单复数的匹配例如:
compan(y|ies)
注意:在大多数的sed和grep版本中,不能对加圆括号的一组字符应用数量词。但是在awk和egrep的所有版本中,都是可以的。
测试:使用前文讨论过的新的元字符来重新构建搜索单个单词的正则表达式。>想打印,<表示不想打印
[root@localhost opt]# cat book.list
>This file tests for book in various places, such as
>book at the beginning of a line or
>at the end of a line book,
>as well as the plural books and
<handbooks.Here are some
<phrases that use the word in different ways:
>"book of the year award"
>to look for a line with the word "book"
>A GREAT book!
>A great book? No.
>told them about (the books) until it
>Here are thr books that you requested
>Yes,it is a good book for children
>amazing that it was called a "harmful book" when
>once you get to the end of the book, you can't believe
<A well-written regular expression should
<avoid mathing unrelated words,
<such as booky(is that a word?)
<and bookish and
<bookworm and so on.
################################################
[root@localhost opt]# grep ' book.* ' book.list
>This file tests for book in various places, such as
>as well as the plural books and
>A great book? No.
>told them about (the books) until it
>Here are thr books that you requested
>Yes,it is a good book for children
>amazing that it was called a "harmful book" when
>once you get to the end of the book, you can't believe
<such as booky(is that a word?)
<and bookish and
它只是打印我们想要匹配行的13行中的8行,并打印我们不想匹配行中的2行,这个表达式匹配包含单词“booky”和“bookish”的行,他忽略了行开始或者结束出的“book”,当涉及某种标点符号时它忽略“book”。
为了进一步限制搜索,我们必须使用字符类,一般地,可以结束单词的字符列表是标点符号。例如;
? . , ! ; : '
另外,引号,圆括号,大括号和方括号可以包围一个单词出现在单词的左侧或者右侧:
" () {} []
你还必须调整单词的复数或者是所有格形式。
因此,应该有两个不同的字符类,单词之前和单词之后。记住我们必须做的就是列出方括号中的类的成员,在单词前面使用:
["[{(]
在单词后面使用:
[]})"?!.,;:' s ]
注意:在类中第一个位置放置闭方括号,表示它是类的成员而不是闭方括号。将以上的类放置在一起,得到如下的正则表达式:
["[{(]*book[]})"?!.,;:' s]*
[root@localhost opt]# grep " [\"[{(]*book[]})\"?\!\.\,;\:' s]* " book.list
>This file tests for book in various places, such as
>as well as the plural books and
>A great book? No.
>told them about (the books) until it
>Here are thr books that you requested
>Yes,it is a good book for children
>amazing that it was called a "harmful book" when
>once you get to the end of the book, you can't believe
我们排除了我们不想要的行,但是都是由在行的开始或结尾处出现的字符串所导致的错误。因为在行的开始处或者结尾处没有空格。所以模式不被匹配,可以使用定位元字符^和$。因为要匹配一个空格或行的开始或者结尾,可以使用egrep并指定的“或”元字符,同时用圆括号分隔。例如:为了匹配行的开始或者一个空格,可以编写下面的表达式:
(^| )因为|和()是元字符扩展集的一部分,所以如果使用的是sed,则必须编写不同的表达式来处理每一种情况。
因此表达式如下:
[root@localhost opt]# egrep "(^|)[\"[{(]*book[]})\"?\!\.\,;\:' s]*( |$)" book.list
>This file tests for book in various places, such as
>book at the beginning of a line or
>at the end of a line book,
>as well as the plural books and
>"book of the year award"
>to look for a line with the word "book"
>A GREAT book!
>A great book? No.
>told them about (the books) until it
>Here are thr books that you requested
>Yes,it is a good book for children
>amazing that it was called a "harmful book" when
>once you get to the end of the book, you can't believe
匹配的范围
A*Z这个表达式匹配“零次或者多次出现的A,同时A后面跟字符串Z”。它产生的结果与仅仅指“Z”是相同的。字符A可以在那里也可以不在那里,事实上,字符Z是唯一匹配的字符。
例如:
[root@localhost opt]# grep 'A*Z' hello
All of us,including Zippy,our dog
some of us ,including Zippy,our dog
如果我们想要匹配的范围扩展到从A到Z,则需要修改正则表达式为:A.*Z
" .* "可以解释为出现零次或者多次的任意字符,这意味着可以找到“出现任意次的字符”,包括什么也没有的情况。整个表达式表示A和Z之间有任意数目的字符,“A”是模式中的开始字符,“Z”是最后一个字符,在它们之间可以有任意个字符或者是没有字符。
[root@localhost opt]# grep 'A.*Z' hello 红色字体表示匹配的范围
All of us,including Zippy,our dog
匹配的范围从A到Z,相同的正则表达式还匹配下面的行
[root@localhost opt]# grep 'A.*Z' hello
i heard it on radio station WVAZ ^^ 1060
字符串A.*Z匹配A后面跟有任意个字符(包括零个字符),再跟有Z的模式:
[root@localhost opt]# grep 'A.*Z' hello
All of us,including Zippy,our dog
i heard it on radio station WVAZ ^^ 1060
All of us, including Zippy and Ziggy
All of us, including Zippy and Ziggy and Zelda
注意:正则表达式A.*Z在每种情况下都匹配可能为最长的范围。当我们想要匹配最短的范围时会出问题。
限制范围
前面说过,正则表达式尝试匹配最长的字符串,并且这可能会引起意想不到的问题。例如:以下的表达式
" .* "
输入字符串如下:
[root@localhost opt]# cat list1.txt
.Se "Appendix" "Full Program Listings"
要匹配第一个参数,则正则表达式如下:
\.Se ".*"
然而,因为模式中的第二个引号与该行上的最后一个引号匹配,所以它结束匹配整个行。如果知道参数的个数,那么可以对每个进行说明:
\.Se ".*" ".*"
虽然这种方法可以像期望的那样工作,但是每行也许不会有相同书目的参数,省略你只想要第一个参数。这里有一个匹配两个引号之间最短范围的正则表达式:
"[^ "]*"
现在我们来看看两列数字之间使用句点字符(.)作为引导符的几行:
1........5
5.........10
10........20
100.........200
这里匹配引导字符的困难是它们的数量是可变的,假如想用单个制表符取代所有的引导符,则可以按下面的形式编写一个匹配行的正则表达式:[0-9][0-9]*\.\.*[0-9][0-9]*
为了限制匹配,可以指定所有的行共用句点的最小数目:[0-9][0-9]*\.\{5,\}*[0-9][0-9]*这个表达式使用sed中可用的大括号来匹配“一个数字后面至少跟5个句点,然后再跟有一个数字的情况”。
[root@localhost opt]# sed 's/\([0-9][0-9]*\)\.\{5,\}\([0-9][0-9]*\)/\1-\2/' list2.txt
1-5
5-10
10-20
100-200
使用喜欢的元字符
有用的正则表达式:
州的邮政编码
(空格)[A-Z][A-Z](空格)
城市、州
^ .*,(空格)[A-Z][A-Z]
城市、州、邮编(POSIX/egrep)
^ .*,(空格)[A-Z][A-Z][0-9]{5}(-[0-9]{4})?
月、日、年
[A-Z][a-z]\{3,9\}(空格)[0-9]\{1,2\},(空格)[0-9]\{4\}
美国社会保险号
[0-9]\{3\}-[0-9]\{2\}-[0-9]\{4\}
北美地区电话
[0-9]\{3\}-[0-9]\{4\}
格式化的美元数额
\$[(空格)0-9]*\.[0-9][0-9]
troff嵌入的字体请求
\\f[(BIRP]C*[BW]*
troff的请求
^ \.[a-z]\{2\}
troff 宏
^ \.[a-z12].
带有参数的troff的宏
^ \.[a-z12].(空格)" .*"
HTML嵌入的代码
<[^ >]*>
Ventura Publisher style codes
^ @.*(空格)=(空格).*
匹配空行
^$
匹配整行
^.*$
匹配一个或者多个空格
(空格)(空格)*