4.2 perl--用正则表达式进行匹配
之前我们看到,正则表示的写法的时候用的是//,比如说/fred/,实际上这是m//的简写,就像前面提到的数组qw//一样。同样的,m也可以任何成对或不成对的定界符,比如说m(fred).
我们可以选择模式中不会出现的字符来作为定界符,比如/http:///,可以写为m%http://%。
常见的修饰符
/i 实现大小写无关的匹配
/s 匹配任意字符 因为.不能匹配换行符,而加上这个后,点号就能匹配任意的字符了
/x 容许在模式里随意地加入空字符
/a 选择ASCII码作为解释方式
/p 只会针对特定的正则表达式开启类似自动捕获变量
/g 全局替换
写法:
if (/yes/i)
注意:
#是注释符号,如果需要用的话,可以加上\,或者[#]。 这些修饰符可以放在一起,放在模式末尾,不必在意先后顺序。
Perl从5.14开始,有三种字符解释方式,ASCII,Unicode,locale。下面的修饰符分别告诉采取何种方式解释字符。
use5.014
/\w+/a #仅仅表示A-Z,a-z,0-9
/\w+/u #任何Unicode当中定义为单词的字符
/\w+/l #类似ASCII的版本,但单词字符的定义取决于本地化定义
单个/a修饰符表示按照ASCII方式解释简写意义,如果使用两个/a,则进一步表示仅仅采用ASCII当时的大小写映射处理
/k/aai #只匹配ASCII字符K或k,但不匹配开尔文符号
锚位
通过给定锚位,我们可以让模式仅在指定位置匹配
\A锚位匹配字符串的绝对开头
\z锚位字符串的绝对末尾
\Z锚位字符串绝对末尾,但容许出现换行符
\b是单词的边界锚位,它能匹配任何的那次的首位
\B 非单词边界锚位,它能匹配所有\b不能匹配的位置。
^ 表示行首, $表示末尾,加上m后可以锚定多行的位置, 比如/^fred/m /fred$/m 分别表示锚位与多行的行首和行尾
=~绑定操作符
默认情况下模式匹配的操作对象是$_,而绑定操作符则是告诉perl,拿右边的模式来匹配左边的字符串,而不是匹配$_
例如:
if ($some_other=~/\brub/){
金典的例子:
#! /usr/bin/perl -w
my $what="larry";
while(<>){
if(/\A($what)/){
print "We saw $waht in the beginning of $_";
}
}
这个例子中我比较喜欢$_,这个代表了输入行,自动被存入的。同时还有变量的内插,当然,如果加上=^就更牛逼了
捕获变量
变量$4的意思是模式中第4对括号所匹配的字符串内容,这个内容和模式运行期间反向引用\4所表示的内容是一样的。但他们并非同一个事物的两种名称:\4反向引用是模式匹配期间得到的结果,而$4则是匹配结束后所捕获的内容的索引。
if (/\s(a-zA-Z)+,/){ #捕获的是空白符和逗号之间的单词
print $1;} #$1为捕获的第一个变量
这些捕获的变量通常存活在下次匹配成功为止。如果需要在数行之外使用捕获变量,通常最好的做法就是将它复制到某个普通变量里。
if (/\s(a-zA-Z)+,/){
my $wilma= $1;
不捕获变量
有的时候,圆括号的加入仅仅是为了分组,所以要关闭它的捕获功能,只需要在左括号的后面加上?:来告诉perl这一对圆括号完全是为了分组而存在的,把变量名留出来
例如:
if (/(?:bronoto)?saurus(stedk|burger)/){ #这个里面$1为(stedk|burger)
命名捕获
use 5.010
my $names='Fred or Barney';
if ($names=^m/(?\w+)(?:and|or)(?\w+)/){
say "T sam $+{name1} and $+{name2}";
}
看明白了吗,通过(?PATTERN),其中LABERL可以自行命名,再通过$+{LABEL}来捕获它 在使用捕获标签后,反向引用的用法也随之改变,之前我们用\1或者\g{1}这样的写法,现在我们可以使用 \g{label}的写法
自动捕获变量
$& 字符串实际匹配模式部分会被自动存在
$` 匹配区段之前的的内容存在
$' 匹配区段之后的内容存在
但是呢,一旦用了这些自动捕获变量,其他正则表达式的运行速度就会变慢。
我们可以将这个的命名改一下,一下的是在5.10或以上的版本中使用
$& ${^MATCH}来表示
$` ${^PREMATCH}
$' ${^POSTMATCH}
例如:
use 5.010;
if ("Hello,there,neighbor"=^/\s(\w+),/p){
print "That actually matched '${^MATCH}'.\n"
}
之前看到的三个量词:* + ?
如果这三个量词都不符合要求,我们还可以使用花括号{}形式指定具体的重复次数范围。
例如 /a{5,15}/其为5到15次的a
优先级
圆括号(分组或捕获) (…)(?:…)(?…)
量词 a*,a+,a?,a{n,m}
锚位和序列 abc,^,$,\A,\b,\z,\Z
折一竖线 a|b|c
原子 a,[abc],\d,\1,\g{2}
有的时候加上括号对弄清优先级有好处,但是圆括号的使用同时也会有捕获功能哦
例1:检测,是否能匹配到match
#! /usr/bin/perl
while (<>){
chomp;
if(/(match)/){
print "Matched: |$`<$&>$'|\n";
}else{
print "No match:|$_|\n";
}
}
例2:检测以字母a结尾的单词,
#! /usr/bin/perl
use warnings;
use strict;
while (<>){
chomp;
if (/a\z/){
print;
}
}
例3:以上面的为例子,将其存储在$1里
#! /usr/bin/perl
use warnings;
use strict;
while(<>){
chomp;
if (/([\d\D]+a\z)/){
print "\$1 contains $1\n";
}
}
例4:接着上题,使用命名捕获
#! /usr/bin/perl
use warnings;
use strict;
while (<>){
chomp;
if (/(?[\d\D]*a\z)/){
print "'word' contains $+{name}\n";
}
}
例5:定位以a结尾,但是再将之后的5个字符捕获至一个独立的内存变量
#! /usr/bin/perl
use warnings;
use strict;
while (<>){
chomp;
if (/(?[\d\D]*a)(?\s[\d\D]{4})/){
print "$+{name1} $+{name2}\n";
}
}
例6:输出以空白结尾的行
#! /usr/bin/perl
use warnings;
use strict;
while (<>){
chomp;
if (/([\d\D]*\s\z)/){
print "$1 m\n";
}
}
ps:
- 上面的方法尽管参考,方法肯定不止一个
- 如果跟我一样是菜鸟,请结合我的第之前的博客看如何运行这样的脚本。
- 博文内容为整理的《Perl语言入门》这本书,感谢这个书的作者Randal L等人的付出
个人公众号,比较懒,很少更新,可以在上面提问题,如果回复不及时,可发邮件给我: tiehan@sina.cn