我正在尝试创建一个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;
答案 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;