我需要将正则表达式替换作为变量传递:
sub proc {
my $pattern = shift;
my $txt = "foo baz";
$txt =~ $pattern;
}
my $pattern = 's/foo/bar/';
proc($pattern);
Run Code Online (Sandbox Code Playgroud)
当然,这不起作用.我试着评估替换:
eval("$txt =~ $pattern;");
Run Code Online (Sandbox Code Playgroud)
但那也不起作用.我在这里错过了多么可怕的事情?
Joh*_*usa 32
我需要将正则表达式替换作为变量传递
你呢?为什么不传递代码参考?例:
sub modify
{
my($text, $code) = @_;
$code->($text);
return $text;
}
my $new_text = modify('foo baz', sub { $_[0] =~ s/foo/bar/ });
Run Code Online (Sandbox Code Playgroud)
通常,当你想将"做某事的东西"传递给子程序时(在你的问题的情况下是"正则表达式替换"),答案是传递对一段代码的引用. 高阶Perl是一本关于这个主题的好书.
好吧,您可以使用qr //运算符预编译RE.但你不能传递一个运算符(s ///).
$pattern = qr/foo/;
print "match!\n" if $text =~ $pattern;
Run Code Online (Sandbox Code Playgroud)
但是如果你必须传递替换运算符,那么你要传递代码或字符串:
proc('$text =~ s/foo/bar');
sub proc {
my $code = shift;
...
eval $code;
}
Run Code Online (Sandbox Code Playgroud)
或者,代码:
proc(sub {my $text = shift; $text =~ s/foo/bar});
sub proc {
my $code = shift;
...
$code->("some text");
}
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
这相当直接回答了你的问题.你可以做更多 - 但是当我使用qr // term而不是$ sub_str作为一个简单的文字时,扩展的正则表达式被替换.
我最近需要为具有一些特殊(方言)SQL类型的语句创建一个解析器(测试解析器),识别这样的行,将它分成三个类型名称:
input: datetime year to second,decimal(16,6), integer
Run Code Online (Sandbox Code Playgroud)
我用来演示这个脚本的脚本使用了引用的正则表达式.
#!/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";
}
Run Code Online (Sandbox Code Playgroud)
我们可以争论使用像$ 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;
Run Code Online (Sandbox Code Playgroud)
你可以打电话
replace($string, qr/(\w+)/, sub { "\u\L$1" }, 'g');
Run Code Online (Sandbox Code Playgroud)
请注意,'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;
}
Run Code Online (Sandbox Code Playgroud)
我们来试试吧:
print replace('content-TYPE', qr/(\w+)/, sub { "\u\L$1" }, 'g');
Run Code Online (Sandbox Code Playgroud)
结果:
内容类型
这对我来说很好看.
| 归档时间: |
|
| 查看次数: |
29635 次 |
| 最近记录: |