当前位置:  开发笔记 > 编程语言 > 正文

将正则表达式替换作为Perl中的变量传递?

如何解决《将正则表达式替换作为Perl中的变量传递?》经验,为你挑选了5个好方法。

我需要将正则表达式替换作为变量传递:

sub proc {
    my $pattern = shift;
    my $txt = "foo baz";

    $txt =~ $pattern;
}

my $pattern = 's/foo/bar/';
proc($pattern);

当然,这不起作用.我试着评估替换:

eval("$txt =~ $pattern;");

但那也不起作用.我在这里错过了多么可怕的事情?



1> John Siracus..:

我需要将正则表达式替换作为变量传递

你呢?为什么不传递代码参考?例:

sub modify
{
  my($text, $code) = @_;
  $code->($text);
  return $text;
}

my $new_text = modify('foo baz', sub { $_[0] =~ s/foo/bar/ });

通常,当你想将"做某事的东西"传递给子程序时(在你的问题的情况下是"正则表达式替换"),答案是传递对一段代码的引用. 高阶Perl是一本关于这个主题的好书.


这有效,并且最接近我的想法.然而,由此产生的代码有点时髦,并且因为我的口味而复杂,我通常认为是时候重新考虑我的整体方法了.

2> zigdon..:

好吧,您可以使用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");
}



3> Jonathan Lef..:
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这样的名字等等.但它完成了这项工作......它不是,也不是生产代码.



4> ephemient..:

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



5> bart..:

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');

结果:

内容类型

这对我来说很好看.

推荐阅读
携手相约幸福
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有