问题描述
我正在使用qr
在脚本中定义正则表达式,并将其推入数组。但是现在看来,如果我不将正则表达式放在双引号中,则将其压入数组的操作会对其进行更改。示例:
#!/usr/bin/perl
use strict; use warnings;
use Data::Dumper qw(Dumper);
use Data::Dumper::Concise;
my @regexes;
my $rgx = 'dog'; my $mdf = 'i';
$rgx = join ( '','(?',$mdf,')',$rgx ) if ($mdf); # in production,$mdf Could be empty
eval { $rgx = qr/$rgx/ };
if ($@) # catch illegitimate regex modifier,such as 'g'
{
die "rgx==$rgx; mdf==$mdf; qr throws an error";
}
push @regexes,$rgx;
push @regexes,"$rgx";
print "first try just printing \$rgx\n";
print " no double quotes:";
print $rgx; print "\n";
print "yes double quotes:";
print "$rgx"; print "\n";
print "but Now see what happens when I push it onto an array\n";
print Dumper \@regexes;
这将产生什么:
first try just printing $rgx
no double quotes:(?^:(?i)dog)
yes double quotes:(?^:(?i)dog)
but Now see what happens when I push it onto an array
[
qr/(?i)dog/i,"(?^:(?i)dog)"
]
我认为(?^:(?i)dog)
是成品,可以进行正则表达式匹配,例如
if ( /$rgx/ )
,实际上,这就是为什么我通过qr
运行预期的正则表达式。
push
为什么要更改它?
为什么会产生特定的语法,
qr/(?i)dog/i
?
解决方法
您实际上是在询问传回的值之间的差异
my $rgx = qr/$rgx/; $rgx
和
my $rgx = qr/$rgx/; "$rgx"
qr//
编译提供的正则表达式模式,并返回一个代表已编译表单的对象。这是存储在变量$rgx
中的值,由表达式$rgx
返回。
""
生成一个字符串,因此"$rgx"
提供了$rgx
的字符串化。值得庆幸的是,这将返回一个字符串,该字符串可用作已编译对象表示的正则表达式模式。但是,通过执行"$rgx"
,您实际上可以撤消qr/$rgx/
所做的工作。
Data :: Dumper使用qr//
文字表示正则表达式对象,并使用""
文字表示字符串。
不同表示形式的模式相同。 Data::Dumper
对对象进行特殊的字符串表示,而在对它进行插值时,正则表达式对象本身也会创建不同的表示。
也许我来自有效Perl 的文章可以帮助您:Let perl create your regex stringification
,由于我在回答自己的问题,所以我可能对海报(我自己)不敬。我问了两个问题。
第一个答案是:“取消提问。push
不会不更改正则表达式。”
第二个答案是:同样,push
不会产生该特定语法。 Data::Dumper
包产生了令人费解的语法。
以下代码对此进行了演示。
#!/usr/bin/perl
use strict; use warnings;
use Data::Dumper qw(Dumper); use Data::Dumper::Concise;
my $rgx = 'dog';
my $mdf = 'is';
$rgx = join ( '','(?',$mdf,')',$rgx ) if ($mdf); # in production,$mdf could be empty
print " no quotes rgx=="; print $rgx; print ";\n"; print " quotes rgx=="; print "$rgx"; print ";\n";
print "DD no quotes rgx=="; print Dumper $rgx; print "DD quotes rgx=="; print Dumper "$rgx";
$rgx = qr/$rgx/;
print "\nNow,after qr:\n";
print " no quotes rgx=="; print $rgx; print ";\n"; print " quotes rgx=="; print "$rgx"; print ";\n";
print "DD no quotes rgx=="; print Dumper $rgx; print "DD quotes rgx=="; print Dumper "$rgx";
及其打印内容:
no quotes rgx==(?is)dog;
quotes rgx==(?is)dog;
DD no quotes rgx=="(?is)dog"
DD quotes rgx=="(?is)dog"
Now,after qr:
no quotes rgx==(?^:(?is)dog);
quotes rgx==(?^:(?is)dog);
DD no quotes rgx==qr/(?is)dog/si
DD quotes rgx=="(?^:(?is)dog)"
已经说过qr
“编译”一个正则表达式。由于我以前作为学生使用汇编语言(FORTRAN,Pascal)编写代码的经历,我认为我对该术语有误解。从https://perldoc.perl.org/perldata#Scalar-values,
标量不一定是一回事。没有地方将标量变量声明为“字符串”类型,“数字”类型,“引用”类型或其他任何类型。由于标量的自动转换,返回标量的操作不需要关心(实际上也不需要关心)其调用者是在寻找字符串,数字还是引用。 Perl是上下文多态的语言,其标量可以是字符串,数字或引用(包括对象)。
如果我没看错的话,qr
的输出将不是“二进制”或类似于Pascal目标代码的输出。 print
正是在示例代码中显示的内容。
因此,我以为push
是一个有罪的聚会而偏离了基础。看来Dumper
通过将某些标量恰好可解释为正则表达式,可以自动将其转换为正斜杠,方法是将它们放在正斜杠中。而且Dumper
显然是从正则表达式的括号内复制正则表达式标志,对其进行重新排序(请注意,它会将double标志从is
更改为si
),并将其放在第二个正后斜线。