精通正则表达式四:环视功能
环视功能的介绍
环视有下面四种类型
(?=...) 肯定顺序环视,子表达式能匹配右侧的文本
(?!...) 否定顺序环视,子表达式不能匹配右侧的文本
(?<=...) 肯定逆序环视,子表达式能匹配左侧的文本
(?<!...) 否定逆序环视,子表达式不能匹配左侧的文本
同样,先举例子:
这是一个肯定顺序环视,如果a的右侧是数字,那么就能匹配到a。
再来看一下否定顺序环视,其实根据上面就很好理解,如果a的右侧不是数字,那么就匹配a:
结果正如所预料的那样,但要注意的是,a的左侧没有字符也匹配了,所以‘(?!\d)’与‘\D’是不同的,‘\D’表达的是某个数字不是字符,但前提是要有这个字符:
逆序环视和顺序环视是类似的,只不过它匹配的是左侧的文本,这里不做过多演示,而且在RegExr上也不支持逆序环视。
环视不会占用字符
通过上面的例子,我们还可以发现,环视不会占用字符,也就是说,环视它就是看一下是不是,但并不会匹配它,也就不会占用这个字符:
可以看到,肯定环视中的‘\d’并没有匹配字符,而是后面的那个‘\d’匹配了。
应用
先来看一个简单的例子,比如我要将Toms改为Tom’s,就可以用环视来解决:
my $name = 'Toms';
$name =~ s/(?<=Tom)(?=s)/'/g;
这样看来环视的作用并不是很大,因为不用环视也能完成这项工作并且也不复杂:
my $name = 'Toms';
$name =~ s/(Tom)(s)/$1'$2/g;
在来看一个例子,就能体会环视的作用了,它采用的就是环视不占用字符的特点,在数值间插入逗号,比如‘12345678’变为‘12,345,678’。
逗号插入的位置有这样的特点,左边是数字,右边的数字是三的倍数,如果不用环视来匹配的话,要这样
my $num = 12345678;
$num =~ s/(\d)((\d\d\d)+\b)/$1,$2/g
但这样能加入所有的逗号吗?答案是否定的,因为‘(\d\d\d)+\b’已经将后面的字符都占用了,就不会再次匹配。但它也可以完成,过要加一个while循环不断匹配,直到匹配不上为止:
while($num =~ s/(\d)((\d\d\d)+\b)/$1,$2/g){}
接下来用环视来做,
my $num = 12345678;
$num =~ s/(?<=\d)(?=((\d\d\d)+$))/,/g;
因为RegExr上不支持逆序环视,所以也可以这样:
my $num = 12345678;
$num =~ s/(\d)(?=((\d\d\d)+$))/$1,/g;
看看匹配结果:
正是我们所需要的将‘2’和‘5’替换为‘2,’和‘5,’。
如果要将一个文件中所有的数字都加上逗号,可以在终端用一条命令完成:
perl -p -i -e 's/(?<=\d)(?=((\d\d\d)+\b))/,/g' word.txt
虽然不用环视也能完成,但效率明显要低很多!

浙公网安备 33010602011771号