我需要将正则表达式替换作为变量传递:
sub proc { my $pattern = shift; my $txt = "foo baz"; $txt =~ $pattern; } my $pattern = 's/foo/bar/'; proc($pattern);
当然,这不起作用.我试着评估替换:
eval("$txt =~ $pattern;");
但那也不起作用.我在这里错过了多么可怕的事情?
我需要将正则表达式替换作为变量传递
你呢?为什么不传递代码参考?例:
sub modify { my($text, $code) = @_; $code->($text); return $text; } my $new_text = modify('foo baz', sub { $_[0] =~ s/foo/bar/ });
通常,当你想将"做某事的东西"传递给子程序时(在你的问题的情况下是"正则表达式替换"),答案是传递对一段代码的引用. 高阶Perl是一本关于这个主题的好书.
好吧,您可以使用qr //运算符预编译RE.但你不能传递一个运算符(s ///).
$pattern = qr/foo/; print "match!\n" if $text =~ $pattern;
但是如果你必须传递替换运算符,那么你要传递代码或字符串:
proc('$text =~ s/foo/bar'); sub proc { my $code = shift; ... eval $code; }
或者,代码:
proc(sub {my $text = shift; $text =~ s/foo/bar}); sub proc { my $code = shift; ... $code->("some text"); }
sub proc { my($match, $subst) = @_; my $txt = "foo baz"; $txt =~ s/$match/$subst/; print "$txt\n"; } my $matcher = qr/foo/; my $sub_str = "bar"; proc($matcher, $sub_str);
这相当直接回答了你的问题.你可以做更多 - 但是当我使用qr // term而不是$ sub_str作为一个简单的文字时,扩展的正则表达式被替换.
我最近需要为具有一些特殊(方言)SQL类型的语句创建一个解析器(测试解析器),识别这样的行,将它分成三个类型名称:
input: datetime year to second,decimal(16,6), integer
我用来演示这个脚本的脚本使用了引用的正则表达式.
#!/bin/perl -w use strict; while (<>) { chomp; print "Read: <$_>\n"; my($r1) = qr%^input\s*:\s*%i; if ($_ =~ $r1) { print "Found input:\n"; s%$r1%%; print "Residue: <$_>\n"; my($r3) = qr%(?:year|month|day|hour|minute|second|fraction(?:\([1-5]\))?)%; my($r2) = qr% (?:\s*,?\s*)? # Commas and spaces ( (?:money|numeric|decimal)(?:\(\d+(?:,\d+)?\))? | int(?:eger)? | smallint | datetime\s+$r3\s+to\s+$r3 ) %ix; while ($_ =~ m/$r2/) { print "Got type: <$1>\n"; s/$r2//; } print "Residue 2: <$_>\n"; } else { print "No match:\n"; } print "Next?\n"; }
我们可以争论使用像$ r1这样的名字等等.但它完成了这项工作......它不是,也不是生产代码.
eval "$txt =~ $pattern";这变成了
eval "\"foo baz\" =~ s/foo/bar/"和替换不适用于文字字符串.
这可行:
eval "\$txt =~ $pattern"但那不是很讨人喜欢.eval几乎不是正确的解决方案.
zigdon的解决方案可以做任何事情,如果替换字符串是静态的,Jonathan的解决方案是非常合适的.如果你想要比第一个更有条理的东西,比第二个更灵活,我会建议混合:
sub proc { my $pattern = shift; my $code = shift; my $txt = "foo baz"; $txt =~ s/$pattern/$code->()/e; print "$txt\n"; } my $pattern = qr/foo/; proc($pattern, sub { "bar" }); # ==> bar baz proc($pattern, sub { "\U$&" }); # ==> FOO baz
s///
不是正则表达式.因此,您不能将其作为正则表达式传递.
我不喜欢eval
这个,它非常脆弱,有很多边框.
我认为最好采用类似于Javascript的方法:传递一个正则表达式(在Perl中,也就是说qr//
)和替换的代码引用.例如,传递参数以获得相同的效果
s/(\w+)/\u\L$1/g;
你可以打电话
replace($string, qr/(\w+)/, sub { "\u\L$1" }, 'g');
请注意,'g'修饰符实际上并不是正则表达式的标志(我认为将它附加到正则表达式是Javascript中的设计错误),所以我选择在第3个参数中传递它.
确定API后,接下来可以执行:
sub replace { my($string, $find, $replace, $global) = @_; unless($global) { $string =~ s($find){ $replace->() }e; } else { $string =~ s($find){ $replace->() }ge; } return $string; }
我们来试试吧:
print replace('content-TYPE', qr/(\w+)/, sub { "\u\L$1" }, 'g');
结果:
内容类型
这对我来说很好看.