括号及反向引用
括号的两种用途
到目前为止,我们已经见过括号的两种用途:
- 限制多选项的范围
- 将若干个字符 组合为一个单元,受量词(问号
?
,加号+
,星号*
)的作用下面来介绍括号的另一种用途,虽然它在
egrep
中并不常见(不过流行的GNU版本的确支持这一功能),但在其他工具软件中很常见。
在许多流派的正则表达式中,括号能够”记住”它们包含的子表达式匹配的文本。
反向引用
下面来看看 backwardReference.txt中的两个句子:
The next step is to put the the
ory into practice
we think that that
standard has been met here
现在我们想找出上面两个相邻重复出现的单词,例如第一句中找出两个相邻的the
,可以看到the theory这两个单词中满足要求。这时候可以使用正则表达式the.the
可以满足上面的要求。同样的如果要找出第二句中两个相邻的that
可以使用that.that
这个正则表达式。
实例如下
egrep "the.the" backwardReference.txt
egrep "that.that" backwardReference.txt
下面来看一个效果一样的操作:egrep "(that).\1" backwardReference.txt
那(that).\1
这个正则表达式是什么东西呢?这个叫做反向引用。
在支持反向引用的工具软件中,括号
()
能”记住”该括号中的子表达式匹配的文本,这下括号记住的文本可以使用元字符\1
进行引用。
当然在一个正则表达式中,我们可以使用多个括号,这样的话,可以用\1
匹配第一个括号中的文本,用\2
匹配第二个括号中的文本,用\3匹配第3个括号中的文本,以此来推。
括号是按照开括号(
出现从左到右进行编号的,所以在([a-z])(0-9)\1\2
这个正则表达式中\1
表示[a-z]
匹配的内容,\2
表示[0-9]
匹配的内容给
反向引用实例:选出相邻的重复的单词
下面来看例子
The next step is to put the theory into practice
we think that that standard has been met here
ha ha ha ni ni ha ni ha ni
现在要求把上面所有的相邻的单词都选出来。我们知道that.that
可以选出两个相邻的that,使用反向引用后可以使用(that).\1
这个正则表达式进行匹配。现在要支持所有的单词,那可以使用字符组来替代前面的单词that
实现,得到新的正则表达式([a-zA-Z]+).\1
这样就能匹配多个单词了。
命令:egrep "([a-zA-Z]+).\1" backwardReference.txt
,效果如下。
可以看到上面匹配出来的不是一个一个单词,两个相邻的字母也匹配出来了,这时可以再加入前面介绍的单词分界符,进行限定。
命令:egrep "\<([a-zA-Z]+).\1\>" backwardReference.txt
这样就可以选出两个相邻的相同单词了,但是还有问题,上面的正则表达式中只能选出第1对相邻的单词,如果有多个两两相邻的单词,就不能正确的选出。这样我们再在上面的正则表示式中加入量词+
,
命令: egrep "\<([a-zA-Z]+)(.\1)+\>" backwardReference.txt
\<([a-zA-Z]+)(.\1)+\>
这个正则表达式中,([a-zA-Z]+)
表示一个单词,(.\1)
中,用点号.
来匹配一个空格,\1
表示前面的([a-zA-Z]+)
这个正则表示式匹配的单词。也就是重复的单词。而(.\1)+
则表示匹配一个或者多个空格
然后是这个重复的单词
。然后使用\<
和\>
限定按照一个个的单词进行匹配。
转义符\
如果需要匹配的某个字符本省就是元字符,那正则表示式该怎样处理?例如,想要检索互联网主机名aa.bb.com
,但是使用aa.bb.com匹配的结果可能是xixixi_aa_bb_com.com
。这是因为点号.
本身就是元字符,他可以匹配任何字符,包括空格等等。所以上面的点号.
号都匹配到下划线了_
,所以xixixi_aa_bb_com.com
也是能匹配上的。
实例:
ESC.txt:
aa.bb.com
xixixi_aa_bb_com.com
命令:egrep "aa.bb.com" ESC.txt
可以在点号前面加上反斜杠\
消去点号的特殊意思,这样就能匹配到点号了,所以正确的正则表示式为:aa\.bb\.com
命令:egrep "aa\.bb\.com" ESC.txt
这里的反斜杠\
称为转义符,对所有的元字符都有效,它可以使得作用的元字符失去该元字符具有的特殊含义,变成普通字符,也就是该字符本身。
还有一个就是在字符组中的反斜杠不具有转义符的性质,也就是说[...\...]
中的\
是普通字符,只匹配该字符本身。
我们还可以转移符来匹配括号,例如\([a-zA-Z]+\)
,就能匹配到(very)
,因为这里开闭括号前面有转移符\
消除了开闭括号的特殊意义,于是他们能匹配文本中的开闭括号。
如果反斜杠后面紧跟的不是元字符,反斜杠的意义就依程序的版本而定,例如我们已经知道,某些版本的程序把\<
,\>
,\1
当做元字符对待。