一个例子:检索某台服务器上的页面重复的单词如"The the"。可能会有很多特俗的要求比如:
正则表达式只需要一个简单的命令,就能检查所有的文件,获得需要知道的结果。时间效率更高。
正则表达式 和 工具 的结合可以极大地提高解决文字问题的效率。
作为编程语言的正则表达式
如果看到正则的神奇功能类似于变魔术的话,那么魔术本身其实并不神奇。只要你懂得如何在手里藏一张牌。
以文件名作类比
“.txt”能够用来选中多个文件。在此类文件名(称为“文件群组”file globs或通配符wildcards)中,有些字符具有特殊的意义。星号表示“任意文本”,问号表示”任意单个字符“。
以语言作类比
完整的正则表达式由两种字符构成:特殊字符(specialcharacters,例如文件名例子中的星号)称为***元字符***,其他为文字(literal),或者是普通文本字符。正则表达式与文件名模式的区别在于:正则表达式的元字符提供了更强大的描述能力。文件名模式只为有限的需求提供了有限的元字符,但是正则表达式语言为高级应用提供了丰富而且描述里极强的元字符。
为了便于理解我们可以把正则表达式想象成普通的语言,普通字符对应语言中的单词,而元字符对应语法。根据语言的规则,按照语法把单词组合起来,就会得到能传达思想的文本。
**
**
完整的正则表达式由小的构建模块(building block unit)组成。每隔单独的构建模块都很简单,不过因为它能够以无穷多的方式组合,将他们组合起来实现特殊目标必须依靠经验。
检索文本文件
Eregp的使用例子,在Linux中用命令行在文件中查找匹配给定正则表达式的行,并高亮显示出来的一个程序。
行的起始和结束:
脱字符号^和美元符号$。
“”用来把匹配文本(这个表达式的其他部分匹配的字符)“锚定”在这一行的开头。正则表达式“cat”最好以下面的方法来理解:
匹配以’c’作为一行的第一个字符,紧接一个a,紧接一个t的文本。
脱字符号和美元符号的特别之处在于它们匹配的是一个位置,而不是具体的文本。
这里是中括号里面的字符的用法。字符组内的元素是“或”的意思。只要其中某个存在就匹配。
一个字符组内可以出现任意个字符如:[1234567]匹配1到7的任意一个数字。
表达式:""
等。"
在字符组内部,字符组元字符(character-class metacharacter)’-’(连字符)表示一个范围:'
与
是完全一样的。还有其他常见用法[0-9]
、[a-z]
等等。
注意:只有在字符组内部,连字符才是元字符,否则它是普通字符。但是,如果连字符出现在字符组内部的开头,那么它还是普通字符。
用[^...]
取代[...]
,这个字符组就会匹配任何未列出的字符。例如,[^1-6]
匹配除了数字1到6以外的任何字符。这个字符组开头的^
表示排除(negate),所以这里列出的是不希望匹配到的字符。
要注意脱字符^
在字符组内部和外部的情况,他在字符组内部的第一个开始位置。
记住:排除型字符组表示“匹配一个未列出的字符(match a character that’s not listed)”,而不是“不要匹配列出的字符”。字符组还是要占据一个位置的。它包含“排除型字符组中所有字符”以外的字符。
例子:正则表达式'q[^u]'
不匹配Iraq
。因为字符q
后面没有字符,但是正则表达式的意思是要匹配一个非q
的字符。
元字符·
(通常称为点号或小点)是用来匹配任意的字符组的简便写法。
例子:如果我们需要搜索03/19/76、03-19-76
,不怕麻烦的话用一个明确容许’-’、’-’、’.'的字符组来构建正则表达式,例如03[-./]19[-./]76
。也可以简单滴尝试03.19.76
。
注意上面的例子中:03[-./]19[-./]76
,点号并不是元字符,因为它们在字符组内部(记住,在字符组内部和外部,元字符的定义和意义是不一样的)。这里的连字符同样也不是元字符,因为它们都紧接在[
或[^]
之后。如果连字符不在字符组的开头,他就是用来表示范围的。
虽然上面的两个正则表达式都能匹配,但是它们的精确程度不一样,点字符的写法显然更广的范围。该使用那个表达式,取决于对欲检索文本的了解程度与检索精确性之间的权衡。例如,如果我们知道,针对某个检索文本03.19.76
这个正则表达式不可能匹配不期望的结果,使用它就是合理的。因此,清楚地了解目标文本是很重要的。
|
是一个非常间接的元字符,它的意思是“或”,依靠它,我们可以把不同的子表达式组合成一个总表达式,这个总表达式能够匹配任意子表达式。在这样的组合中,子表达式称为“多选分支”。
回头来看gr[ea]y
的例子,有意思的是,他还可以用grey|gray
,或者是gr(a|e)y
来实现。后者用括号来划定多选结构的范围(正常情况下,括号也是元字符)。请注意gr[a|e]y
不符合我们的要求–在这里,|
只是一个和a
与e
一样的普通字符。
对于表达式gr[a|e]y
来说,括号是必须的,因为如果没有括号,gra|ey
的意思就成了“gra
或者ey
”,而这不符合我们的要求。另一个例子:(First|1st)。[Ss]treet
。(正则表达式里面的句号表示空格)。上面的正则表达式中由于有相同的结尾st
所以可以写成(Fir|1)st。[Ss]treet
。
gr[ea]y
和gr(e|a)y
的例子可能会让人觉得多选结构和字符组没太大区别,但是请留神不要混淆这两个概念。一个字符组只能匹配目标文本中的单个字符,而每个选择结构自身都可能是完整的正则表达式,都可以匹配任意长度的文本。
字符组基本可以算是一门独立的微型语言(例如,对于元字符,它们有自己的规定)。多选结构是“正则表达式语言主体(main regular expression language)”的一部分。
同样,在一个包含多选结构的表达式中使用脱字符和美元符号的时候要小心。比较^From|Subject|Date:。
和^(From|Subject|Date):。
就会发现,虽然它们看起来与匹配Email的例子很相似,匹配结果(即它们的用处)却大不相同。第一个表达式其实是|From
或Subject
或Date:。
,实用性不大。我们希望每个多选分支之前都有一个脱字符,之后有:。
,所以应该使用括号来“限制”这些多选分支。第二个正则表达式才具有:“匹配以From:。
或者Subject:。
或者Date:。
”开头的文本行的意思。这是我们想要的结构。
该功能不是正则表达式语言的一部分,却是许多工具软件提供的有用的相关特性。egrep的命令行参数"-i"表示进行忽略大小写的匹配。把-i
写在正则表达式之前:
egrep -i '^(From|Subject|Date): ' mailbox
使用正则表达式经常会遇到一个问题,期望匹配的“单词”包含在另一个单词之中。在cat
,gray
和Smith
的例子中。单词分解符:单词开头和结束的位置。
类似于句子的开头和结束即(^
和$
),可以对单词的开头和结束进行匹配。如果egrep支持“元字符序列”\<
和\>
,就可以用它们来匹配单词分界的位置。
\
的意思是:匹配单词的开头位置,然后是cat
这三个字母,然后是单词的结束位置。
请注意:<
和>
本身并不是元字符–只有当它们与斜线结合的时候,整个序列才具有特殊意义。这也是被称为“元字符序列的原因”。重要的是它们的特殊意义而不是字符的个数。
“单词的开始和结束”准确的说是“字母数字的开始和结束”,不过这样说太麻烦了。