之前看一些教程的时候,关于参数/g,一般会在替换那一章中提到,也就是s///g,表示全局不重复匹配及替换 (第一个区域匹配成功之后,再用第二个"//"区域内的值把匹配到的部分替换掉),也就是说对整个作用的标量进行多次匹配,找出所有满足匹配条件的段,再进行替换。
如果验证此表达式的返回值,则可以得到替换成功的次数,参见如下代码(\w表示数字,字母,下划线中的任一字符):
$string = "abcde fghij";
$times = $string =~ s/\w//g;
print $times;
==>执行之后得到的值为10。
但是放在弹出的匹配中又有什么作用呢?会不会同样返回匹配成功的次数呢?用代码进行测试:
$string = "abcde fghij";
$times = $string =~ /\w/g;
print $times;
==〉执行之后得到结果1。表示匹配成功,并不会返回匹配到的次数。
这么看来放在匹配中,/g似乎没有什么特别的作用, 不过一次被别人叫去看题,发现一个很有趣的现象,匹配中使用/g同样有办法得到匹配到的次数。
先看一个不用/g的例子:
$string = "abcde fghij";
while($string =~ /\w/){
$count ++ ;
print "loop $count:\n"; #just for debugging;
}
print $count;
==〉执行此脚本,会进入到无尽循环,count的值递增,屏幕一直打印出“loop 次数”.
这样的结果很好理解,因为最初条件为真,而且在循环体中并没有改变掉$string 的内容,故而循环条件恒真。
再看下面的例子(加上/g):
$string = "abcde fghij";
while($string =~ /\w/g){
$count ++ ;
print "loop $count:\n"; #just for debugging;
}
print $count;
==>执行结果:一共显示10次loop,最后$count的值为10。(也就是字符的个数)
可能会有人认为那是因为加上了g, $string的内容在每次循环中都发生了变化,现在来验证这一点:
$string = "abcde fghij";
while($string =~ /\w/g){
$count ++ ;
print "loop $count:$string\n"; #just for debugging;
}
print "$string\n";
print $count;
==〉执行结果:
$ perl g.pl
loop 1:abcde fghij
loop 2:abcde fghij
loop 3:abcde fghij
loop 4:abcde fghij
loop 5:abcde fghij
loop 6:abcde fghij
loop 7:abcde fghij
loop 8:abcde fghij
loop 9:abcde fghij
loop 10:abcde fghij
abcde fghij
10
可以发现实际上每次循环中$string的值都并未发生改变。
继续测试下去会发现有趣且让人费解的现象,应该也是跟perl的内部机制有关。
如果我们在循环体中企图改变$string的值,会发生什么现象呢?参加如下代码:
$string = "abcde fghij";
while($string =~ /\w/g){
$count ++ ;
$string =~ s/e/x/;
print "loop $count:\n"; #just for debugging;
}
print "$string\n";
print $count;
==〉得到的结果:$string 变成 "abcdx fghij", $count 变成 11。
如果就上面的例子,仅仅改动替换表达式中的一个字符,结果就完全不一样了。如:
$string = "abcde fghij";
while($string =~ /\w/g){
$count ++ ;
$string =~ s/./x/;
print "loop $count:$string\n"; #just for debugging;
}
print "$string\n";
print $count;
==〉执行结果:再次陷入了无尽循环。
由此可以推测: 如果原始$string并未改变,那么加上/g之后,条件匹配每次都是从上次匹配的终点开始,如果循环体中$string的值发生变化,那么下一次的条件判断将从$string首开始。
故而,验证:
参加下列代码:
$string = "abcde fghij";
while($string =~ /\w/g){
$count ++ ;
$string =~ s/[a|b|c]/x/;
print "loop $count:$string\n"; #just for debugging;
}
print "$string\n";
print $count;
==〉执行之后,可以发现$count值为13,循环体中的替换将参与最初三次循环。
而改成全局替换:
$string = "abcde fghij";
while($string =~ /\w/g){
$count ++ ;
$string =~ s/[a|b|c]/x/g;
print "loop $count:$string\n"; #just for debugging;
}
print "$string\n";
print $count;
==〉则执行之后,$count的值为11。因此替换只参与了一次循环。