带替换的Perl过滤器

时间:2017-07-22 23:21:14

标签: perl

我正在尝试创建一个Perl脚本,用于过滤STDIN上显示的数据,更改所有出现的内容 一个字符串到另一个字符串并输出所有输入行,更改并更改为STDOUT。 FROMSTRING和TOSTRING可以是PERL兼容的正则表达式。我无法获得匹配的输出。

这是我想要实现的一个例子。

echo "Today is Saturday" | f.pl 'a' '@'

输出Tod@y is S@turd@y

echo io | filter.pl '([aeiou])([aeiou])' '$2$1'

输出oi

#!/usr/bin/perl
use strict;
use warnings;
if (@ARGV != 2){
        print STDERR "Usage: ./filter.pl FROMSTRING TOSTRING\n"
}
exit 1;
my $FROM = $ARGV[0];
my $TO = $ARGV[1];
my $inLine = "";
while (<STDIN>){
$inLine = $_;
$inLine =~ s/$FROM/$TO/;
print  $inLine
}
exit 0;

2 个答案:

答案 0 :(得分:6)

首先,s/.../.../操作的替换部分不是正则表达式;它就像一个双引号字符串。

您的代码存在一些问题。

  • 您的exit 1;语句出现在主代码的中间,而不是出现在错误块中。你可能想要:

    if (@ARGV != 2) {
        print STDERR "Usage: ./filter.pl FROMSTRING TOSTRING\n";
        exit 1;
    }
    
  • 如果您希望在同一行中进行多次替换,则您错过了g标记:

    $inLine =~ s/$FROM/$TO/g;
    
  • 没有必要预先声明$inLine;它只在一个区块中使用。

  • 除了将$_复制到$inLine之外,还无需在$names_like_this中读取一行。
  • $namesLikeThis用于变量和函数,而非$0,这是很常见的。
  • 您可以使用exit 0;代替在错误消息中对程序名称进行硬编码。
  • #!/usr/bin/perl use strict; use warnings; if (@ARGV != 2) { die "Usage: $0 FROMSTRING TOSTRING\n"; } my ($from, $to) = @ARGV; while (my $line = readline STDIN) { $line =~ s/$from/$to/g; print $line; } 最后是多余的。

以下内容更接近我的写作方式:

'$2$1'

尽管如此,这些都没有解决你的第二个例子$to作为替代。上面的代码不会做你想要的,因为$1是一个普通的字符串。 Perl不会扫描它以查找"foo $bar baz"之类的内容并替换它们。

当您在代码中编写'foo ' . $bar . ' baz'时,它与$bar的含义相同,但这仅适用于代码,即字面上出现在源代码中的内容。 \n的内容未在运行时重新扫描以扩展,例如$quux$1。这也适用于'$2$1'和朋友,这只是正常变量。

那么你如何让eval工作?

一种方法是使用eval,但我不喜欢它,因为它是eval:如果你不是很小心,它允许某人通过传递正确的替换&#34;字符串&#34;来执行任意代码。

在没有#!/usr/bin/perl use strict; use warnings; use Data::Munge qw(replace); if (@ARGV != 2) { die "Usage: $0 FROMSTRING TOSTRING\n"; } my ($from, $to) = @ARGV; while (my $line = readline STDIN) { print replace($line, $from, $to, 'g'); } 的情况下执行此操作是可能的,甚至可以轻松实现,例如Data::Munge::replace

replace

$与JavaScript的String#replace类似,因为它扩展了特殊的$to序列。

手动操作也是可能的,但有点烦人,因为您基本上必须将$视为模板并手动展开所有# untested $line =~ s{$from}{ my @start = @-; my @stop = @+; (my $r = $to) =~ s{\$([0-9]+|\$)}{ $1 eq '$' ? '$' : substr($from, $start[$1], $stop[$1] - $start[$1]) }eg; $r }eg; 序列(例如,使用其他正则表达式替换):

${1}

(这不会实现${2}function value(&$param){} value($var['key']); echo array_key_exists("key", $var)? "true" : "false"; //true 等支持的群组。这些是留给读者的练习。)

这段代码非常令人讨厌,因此我更喜欢使用像Data::Munge之类的模块来处理这类事情。

答案 1 :(得分:0)

发现了三个错误:

; after error message
exit 1;
$inLine =~ s/$FROM/$TO/g;

像:

#!/usr/bin/perl
use strict;
use warnings;
if (@ARGV != 2){
        print STDERR "Usage: ./filter.pl FROMSTRING TOSTRING\n";
        exit 1;
}
my $FROM = $ARGV[0];
my $TO = $ARGV[1];
my $inLine = "";
while (<STDIN>){
$inLine = $_;
$inLine =~ s/$FROM/$TO/g;
print  $inLine
}
exit 0;