ASP站长网正则表达式两篇:
基础正则
Perl正则
本文是对Perl正则的一点扩展,主要内容是使用qr//创建正则对象,以及一些其它的技巧。
qr//创建正则对象
因为可以在正则模式中使用变量替换,所以我们可以将正则中的一部分表达式事先保存在变量中。例如:
$str="hello worlds gaoxiaofang";
$pattern="w.*d";
$str =~ /$pattern/;
print "$&\n";
但是,这样缺陷很大,在保存正则表达式的变量中存放的特殊字符要防止有特殊意义。例如,当使用m//的方式做匹配分隔符时,不能在变量中保存/,除非转义。
perl提供了qr/pattern/的功能,它把pattern部分构建成一个正则表达式对象,然后就可以:
在正则表达式中直接引用这个对象
可以将这个对象保存到变量中,通过引用变量的方式来引用这个已保存好的正则对象
将引用变量插入到其它模式中构建更复杂的正则表达式
其中:
qr//的定界符斜线可以替换为其它符号,例如对称的括号类qr() qr{} qr<> qr[],一致的符号类qr%% qr## qr!! qr$$ qr"" qr''等。
但是使用单引号作为定界符时比较特殊(即qr'pattern'),它会将pattern部分使用单引号的方式去解析,例如变量$var无法替换,而是表示4个字符。但是正则表达式的元字符仍然起作用,例如$仍然表示行尾。
$str="hello worlds gaoxiaofang";
# 直接作为正则表达式
$str =~ qr/w.*d/;
print "$&\n";
# 保存为变量,再作为正则表达式
$pattern=qr/w.*d/;
$str =~ $pattern; # (1)
$str =~ /$pattern/; # (2)
print "$&\n";
# 保存为变量,作为正则表达式的一部分
$pattern=qr/w.*d/;
$str =~ /hel.* $pattern/;
print "$&\n";
还允许为这个正则对象设置修饰符,比如忽略大小写的匹配修饰符为i,这样在真正匹配的时候,就只有这一部分正则对象会忽略大小写,其余部分仍然区分大小写。
$str="HELLO wORLDs gaoxiaofang";
$pattern=qr/w.*d/i; # 忽略大小写
$str =~ /HEL.* $pattern/; # 匹配成功,$pattern部分忽略大小写
$str =~ /hel.* $pattern/; # 匹配失败
$str =~ /hel.* $pattern/i; # 匹配成功,所有都忽略大小写
qr如何构建正则对象
输出qr构建的正则引用,看看是怎样的结构:
$patt1=qr/w.*d/;
print "$patt1\n";
$patt2=qr/w.*d/i; # 加上修饰符i
print "$patt2\n";
$patt3=qr/w.*d/img; # 加上修饰符img
print "$patt3\n";
上面的print将输出如下结果:
(?^:w.*d)
(?^i:w.*d)
(?^mi:w.*d)
qr的作用实际上就是在我们给定的正则pattern基础上加上(?^:)并带上一些修饰符,得到的结果总是(?^FLAGS:pattern)。
但是上面patt3的修饰符g不见了。先可以看看(?^:)的作用:非捕获分组,并重置修饰符。重置为哪些修饰符?对于(?^FLAGS:)来说,只有这些修饰符"alupimsx"是可用的,即(?^alupimsx:):
如果给定的修饰符不在这些修饰符内,则不被识别,有时候会报错
如果给定的修饰符属于这几个修饰符,那么没有给定的修饰符部分将采用默认值(不同版本可能默认是否开启的值不同)
所以上面的g会被丢弃,甚至在进一步操作这个正则引用时,会报错。
既然qr给pattern部分加上了(?^:),那么当它们插入到其它正则中的时候,就能保证这一段是独立的,不受全局修饰符影响的模式。
$patt1=qr/w.*d/im;
$patt2=qr/hel.*d $patt1/i;
print "$patt2\n"; # 输出:(?^i:hel.*d (?^mi:w.*d))
正则引用作为标量的用法
既然qr//创建的正则对象引用是一个标量,那么标量可以出现的地方,正则引用就可以出现。例如,放进hash结构,数组结构。
例如,放进数组中形成一个正则表达式列表,然后给定一个待匹配目标,依次用列表中的这些模式去匹配。
use v5.10.1;
my @patterns = (
qr/(?:Willie )?Gilligan/,
qr/Mary Ann/,
qr/Ginger/,
qr/(?:The )?Professor/,
qr/Skipper/,
qr/Mrs?. Howell/,
);
my $name = 'Ginger';
foreach my $pattern ( @patterns ) {
if( $name =~ /$pattern/ ) {
say "Match!";
print "$pattern";
last;
}
}
还可以将这些正则引用放进hash中,为每个pattern都使用key来标识一下,例如pattern1是用来匹配什么的:
use v5.10.1;
my %patterns = (
Gilligan => qr/(?:Willie )?Gilligan/,
'Mary Ann' => qr/Mary Ann/,
Ginger => qr/Ginger/,
Professor => qr/(?:The )?Professor/,
Skipper => qr/Skipper/,
'A Howell' => qr/Mrs?. Howell/,
);
my $name = 'Ginger';
my( $match ) = grep { $name =~ $patterns{$_} } keys %patterns;
say "Matched $match" if $match;
上面将grep语句的结果赋值给了一个标量,所以如果有多个Pattern能匹配$name,多次执行,$match的值将可能会不一样。
构建复杂的正则表达式
有了qr,就可以将正则表达式细化成一小片一小片,然后组合起来。例如:
my $howells = qr/Thurston|Mrs/;
my $tagalongs = qr/Ginger|Mary Ann/;
my $passengers = qr/$howells|$tagalongs/;
my $crew = qr/Gilligan|Skipper/;
my $everyone = qr/$crew|$passengers/;
就像RFC 1738中对URL各个部分的解剖,如果转换成Perl正则,大概是这样的(了解即可):
# 可复用的基本符号类
my $alpha = qr/[a−z]/;
my $digit = qr/\d/;
my $alphadigit = qr/(?i:$alpha|$digit)/;
my $safe = qr/[\$_.+−]/;
my $extra = qr/[!*'\(\),]/;
my $national = qr/[{}|\\^~\[\]`]/;
my $reserved = qr|[;/?:@&=]|;
my $hex = qr/(?i:$digit|[A−F])/;
my $escape = qr/%$hex$hex/;
my $unreserved = qr/$alpha|$digit|$safe|$extra/;
my $uchar = qr/$unreserved|$escape/;
my $xchar = qr/$unreserved|$reserved|$escape/;
my $ucharplus = qr/(?:$uchar|[;?&=])*/;
my $digits = qr/(?:$digit){1,}/;
# 可复用的URL组成元素
my $hsegment = $ucharplus;
my $hpath = qr|$hsegment(?:/$hsegment)*|;
my $search = $ucharplus;
my $scheme = qr|(?i:https?://)|;
my $port = qr/$digits/;
my $password = $ucharplus;
my $user = $ucharplus;
大型站长资讯类网站! https://www.0792zz.cn