我正在尝试overload constants in regular expressions。这是我的Tagger包:
package Tagger;
use overload;
sub import { overload::constant 'qr' => \&convert }
sub convert {
my $re = shift;
$re =~ s/\\nom/((?:[A-Z]{1}[a-z]+\\s*){2,3}(\\((\\w|\\s)+\\)+?)*)/xg;
return $re;
}
1;
这是我想要触发重载的子程序:
sub ChopPattern {
my $string= shift;
my $pattern = shift;
if($string =~ m/$pattern/) {
$string =~ s/$&/ /g;
return ($string, $&);
} else {
return ($string, '');
}
}
这是我的测试:
$test = "foo bar Max Fast bar foo";
($test, $name) = ChopPattern($test, '\nom');
say $test;
say $name;
如果我在子程序的匹配中硬连线测试模式\nom
:
sub ChopPattern {
my $string= shift;
my $pattern = shift;
if($string =~ m/\nom/) {
$string =~ s/$&/ /g;
return ($string, $&);
} else {
return ($string, '');
}
}
测试得出正确的答案:
foo bar bar foo
Max Fast
但如果我在匹配中使用$pattern
,则测试结果为:
foo bar Max Fast bar foo
<null line>
是否有\nom
触发Tagger但是等于\nom
的变量没有的原因?
以下是正在使用的Perl版本的详细信息:
This is perl 5, version 16, subversion 3 (v5.16.3) built for MSWin32-x64-multi-thread (with 1 registered patch, see perl -V for more detail)
Copyright 1987-2012, Larry Wall
Binary build 1604 [298023] provided by ActiveState http://www.ActiveState.com
Built Apr 14 2014 15:29:45
答案 0 :(得分:5)
是否有
的原因\nom
触发Tagger但是等于\nom
的变量没有?
因为'\nom'
是字符串文字,而不是正则表达式的常量部分:
$ perl -Moverload -E'BEGIN { overload::constant qr => sub { say "@_" } } $foo =~ "bar"'
$ perl -Moverload -E'BEGIN { overload::constant qr => sub { say "@_" } } $foo =~ /bar/'
bar bar qq
你正在做的事情是个坏主意。以下实现更容易理解,并且不会在任何地方改变正则表达式语义:
use strict;
use warnings 'all';
use 5.010;
sub chop_pattern {
my ($string, $pattern) = @_;
my %mapping = (
'\nom' => qr/((?:[A-Z][a-z]+\s*){2,3}(?:\([\w\s]+\)+?)*)/
);
if (exists $mapping{$pattern}) {
my $matched = $string =~ s/$mapping{$pattern}/ /g;
return $string, $1 if $matched;
}
return $string, '';
}
my ($string, $chopped) = chop_pattern('foo Bar Baz qux', '\nom');
say "<$string> <$chopped>";
输出:
<foo qux> <Bar Baz >
我猜你是因为想要处理不止一个魔法而超负荷工作的#34;字符串(例如\nom
)。我用一个简单的哈希将字符串映射到正则表达式。
答案 1 :(得分:4)
编程Perl 表示overload::constant
适用于常量。
只要Perl tokener遇到常数,就会调用为integer和float提供的任何处理程序。
当你致电m/$pattern/
时,那不是常数。它是一个变量。
($test, $name) = ChopPattern($test, '\nom');
现在'\nom'
是常量,但它是一个字符串。将其转换为qr//
,您将拥有一个包含常量的正则表达式。
($test, my $name) = ChopPattern($test, qr'\nom');
ChopPattern
中的模式匹配可以保持不变:
if($string =~ m/$pattern/) { ... }
因为现在正则表达式中有一个常量部分,Perl可以调用convert
重载,并执行正则表达式。
让我们看看这一点。记住Perl在编译时解析源代码时会执行这个重载替换。
考虑这个例子:
BEGIN {
overload::constant 'qr' => sub {
my $re = shift;
$re =~ s/\\nom/foobar/;
return $re;
};
}
sub match {
my ( $t, $p ) = @_;
$t =~ m/$p/;
}
match( 'some text', '\nom' );
代码的作用并不重要。当我们解析它时,我们得到这个输出:
$ perl -MO=Deparse scratch.pl
sub BEGIN {
use warnings;
use strict;
use feature 'say';
overload::constant('qr', sub {
my $re = shift();
$re =~ s/\\nom/foobar/;
return $re;
}
);
}
sub match {
use warnings;
use strict;
use feature 'say';
BEGIN {
$^H{'qr'} = 'CODE(0x147a048)';
}
my($t, $p) = @_;
$t =~ /$p/;
}
use warnings;
use strict;
use feature 'say';
BEGIN {
$^H{'qr'} = 'CODE(0x147a048)';
}
match 'some text', '\\nom'; # <-- here
我们可以看到处理程序已安装,但在函数调用的最后一行中,有'\\nom'
字符串。
现在,如果我们使用带引号的表达式qr//
而不是字符串,事情会发生变化。
BEGIN {
overload::constant 'qr' => sub {
my $re = shift;
$re =~ s/\\nom/foobar/;
return $re;
};
}
sub match {
my ( $t, $p ) = @_;
$t =~ m/$p/;
}
match( 'some text', qr/\nom/ );
现在,已解除程序突然包含foobar
。正则表达式发生了变化。
$ perl -MO=Deparse scratch2.pl
sub BEGIN {
use warnings;
use strict;
use feature 'say';
overload::constant('qr', sub {
my $re = shift();
$re =~ s/\\nom/foobar/;
return $re;
}
);
}
sub match {
use warnings;
use strict;
use feature 'say';
BEGIN {
$^H{'qr'} = 'CODE(0x1e81048)';
}
my($t, $p) = @_;
$t =~ /$p/;
}
use warnings;
use strict;
use feature 'say';
BEGIN {
$^H{'qr'} = 'CODE(0x1e81048)';
}
match 'some text', qr/foobar/; # <-- here
在代码运行之前就已经这样做了。
如果我们用-MO=Concise
运行这两个程序来查看解释器在编译后运行的内容,我们会进一步证明这些东西只适用于源代码中的实际常量,并且不能动态工作。
$ perl -MO=Concise scratch.pl
8 <@> leave[1 ref] vKP/REFC ->(end)
1 <0> enter ->2
2 <;> nextstate(main 2529 scratch.pl:5950) v:%,R,*,&,{,x*,x&,x$,$,469762048 ->3
7 <1> entersub[t1] vKS/TARG,2 ->8
- <1> ex-list K ->7
3 <0> pushmark s ->4
4 <$> const(PV "some text") sM ->5 # <-- here
5 <$> const(PV "\\nom") sM ->6
- <1> ex-rv2cv sK/2 ->-
6 <$> gv(*match) s ->7
使用qr//
:
$ perl -MO=Concise scratch2.pl
8 <@> leave[1 ref] vKP/REFC ->(end)
1 <0> enter ->2
2 <;> nextstate(main 2529 scratch2.pl:5950) v:%,R,*,&,{,x*,x&,x$,$,469762048 ->3
7 <1> entersub[t1] vKS/TARG,2 ->8
- <1> ex-list K ->7
3 <0> pushmark s ->4
4 <$> const(PV "some text") sM ->5 # <-- here
5 </> qr(/"foobar"/) lM/RTIME ->6
- <1> ex-rv2cv sK/2 ->-
6 <$> gv(*match) s ->7