Perl就像一把瑞士军刀,临战时用起来很方便。特别在文本处理的时候,比如在大型系统中追踪问题常常以来于系统日志,我们有很多日志,access_log或者err_log或者deploy_log。今天我一边看剧场版的名侦探柯南,一边看了一下Perl的正则表达式匹配的文档,写点笔记,也算这个周末没有完全堕落啊。
先看一个小例子:
"abcde"=~/(abd|abc)(df|d|de)/;意思是匹配的部分有两部分(two groups)组成,第一部分(group)有两种可能(alternatives)分别是abd和abc,第二部分是df或者d或者de。那Perl内部在匹配的时候是经历的怎样一个过程呢?
在Windows XP的cmd下面验证一下:
C:>perl -e "print qq{$1,$2} if q{abcde}=~/(abd|abc)(df|d|de)/"
abc,d
这里要注意几点:
现在我们知道在正则匹配的时候是有一些原则的,比如这里的left most。那我们再看一个例子:
$x="The programming republic of Perl";
$x=~/^(.+)(e|r)(.*)$/;
意思是从字符串头开始匹配1个或多个字符,然后碰到字符e或者r,然后后面跟着0个或多个字符。问题是^(.+)是匹配到programming中的r之前的部分,还是 republic中的r之前的部分,还是Perl中的e之前的部分,还是Perl中的r之前的部分呢??哈哈,好像比前面复杂了哦,这里有4条黄金法则:
为了不误人子弟,我还是贴文档里面的英文吧-:)
我试图以我的理解重新组织一下,在保证能够匹配的前提下,总是试图尽早的匹配,如果在给定位置,有多条路可走,优先走最左边的路,选定了一条路了,就能走多远走多远。
再回来看刚才的例子,尽早匹配,那第一个字符T就匹配上了,^(.+)是贪婪的,能走多远走多远,在满足整体匹配的前提下,一直走到Perl中的r之前。然后(e|r)匹配字符r, (.*)$匹配字符l。
C:>perl -e "print qq{$1,$2,$3} if q{The programming republic of Perl}=~/^(.+)(e|r)(.*)$/"
The programming republic of Pe,r,l
现在我们来做些练习,$x还是等于"The programming republic of Perl":
$x=~/(m{1,2})(.*)$/;
尽早匹配,匹配点是programming中的第一个m,由于贪婪,在既能匹配1个m,又能匹配2个m的情况下,匹配2个m,最后(.*)$匹配剩余的子串。$1=’mm’, $2=’ing republic of Perl’。
$x=~/.*(m{1,2})(.*)$/;
尽早匹配,匹配点是T,由于贪婪,一直匹配到programming中的第一个m,并且试图匹配第二个m,但是他不能这么做,因为这样m{1,2}就不能匹配了,别忘了我们的最高指示是整体匹配,是走出迷宫!于是m{1,2}只能匹配第二个m。最后 $1=’m', $2=’ing republic of Perl’。
$x=~/(.?)(m{1,2})(.*)$/;
(.?)匹配0个或者1个字符,也就是可以匹配programming中的a,也可以是第一个m,但是"尽早匹配"意味着匹配a,从字符a的下一个位置开始匹配m{1,2},因为贪婪,所以要匹配两个m。最后 $1=’a', $2=’mm’, $3=’ing republic of Perl’。
最后看一个例子,"zXXXb"=~/(X*)/;一看很简单嘛,从第一个X开始匹配,因为贪嘛,一直贪3个X,所以(X*)匹配’XXX’ 。可是我错了!
C:>perl -e "print $1 if q{zXXXb}=~/(X*)/"
打出来的是空,空啊,难道是没有匹配?其实我这里就是忘掉了’尽快匹配’,忘掉了第一条matched at the earliest possible position in the string. 因为(X*)的意思是0个或多个X,所以字符z之前的空串也被匹配了,这里$1=空!这里稍加改动,把(X*)改成(X+),就能看到区别:
C:>perl -e "print $1 if q{zXXXb}=~/(X+)/"
XXX
所以最后提醒一下,4条黄金法则中的第一条是最厉害的。我看书还是不够认真,犯了错才看到了这样一句话,就在黄金法则正下方:
As we have seen above, Principle 1 overrides the others — the regexp will be matched as early as possible, with the other principles determining how the regexp matches at that earliest character position.