私は次のことをしたいと思います:
$find = "start (.*) end";
$replace = "foo \1 bar";
$var = "start middle end";
$var =~ s/$find/$replace/;
$var には「foo middle bar」が含まれていると思いますが、機能しません。どちらもしません:
$replace = 'foo \1 bar';
どういうわけか、エスケープに関して何かが欠けています。
私は次のことをしたいと思います:
$find = "start (.*) end";
$replace = "foo \1 bar";
$var = "start middle end";
$var =~ s/$find/$replace/;
$var には「foo middle bar」が含まれていると思いますが、機能しません。どちらもしません:
$replace = 'foo \1 bar';
どういうわけか、エスケープに関して何かが欠けています。
交換側では、\1ではなく$1を使用する必要があります。
そして、あなたはあなたが望む結果を与える評価可能な式を置き換えて、s ///にそれを次のように/ee修飾子で評価するように指示することによってのみあなたが望むことをすることができます:
$find="start (.*) end";
$replace='"foo $1 bar"';
$var = "start middle end";
$var =~ s/$find/$replace/ee;
print "var: $var\n";
""とdouble/eが必要な理由を確認するには、ここでdoubleevalの効果を確認してください。
$ perl
$foo = "middle";
$replace='"foo $foo bar"';
print eval('$replace'), "\n";
print eval(eval('$replace')), "\n";
__END__
"foo $foo bar"
foo middle bar
(池上が指摘しているように、単一の/eまたは二重のeの最初の/eは実際にはeval()
;ではなく、置換が文字列ではなくコンパイルするコードであることをコンパイラに通知します。それでも、eval(eval(...))
なぜ必要なのかを示しています/ eeを希望どおりに機能させるために必要なことを実行します。)
Deparse は、これが実行されていることを示しています。
$find = 'start (.*) end';
$replace = "foo \cA bar";
$var = 'start middle end';
$var =~ s/$find/$replace/;
でも、
/$find/foo \1 bar/
次のように解釈されます。
$var =~ s/$find/foo $1 bar/;
残念ながら、これを行う簡単な方法はないようです。
文字列 eval で実行できますが、危険です。
私のために働く最も正気の解決策はこれでした:
$find = "start (.*) end";
$replace = 'foo \1 bar';
$var = "start middle end";
sub repl {
my $find = shift;
my $replace = shift;
my $var = shift;
# Capture first
my @items = ( $var =~ $find );
$var =~ s/$find/$replace/;
for( reverse 0 .. $#items ){
my $n = $_ + 1;
# Many More Rules can go here, ie: \g matchers and \{ }
$var =~ s/\\$n/${items[$_]}/g ;
$var =~ s/\$$n/${items[$_]}/g ;
}
return $var;
}
print repl $find, $replace, $var;
私の答えで言ったように、私は理由で評価を避けます。
$find="start (.*) end";
$replace='do{ print "I am a dirty little hacker" while 1; "foo $1 bar" }';
$var = "start middle end";
$var =~ s/$find/$replace/ee;
print "var: $var\n";
このコードは、あなたが思っていることを正確に実行します。
置換文字列が Web アプリケーション内にある場合は、任意のコード実行への扉を開いただけです。
よくできた。
また、まさにこの理由から、汚染がオンになっていると機能しません。
$find="start (.*) end";
$replace='"' . $ARGV[0] . '"';
$var = "start middle end";
$var =~ s/$find/$replace/ee;
print "var: $var\n"
$ perl /tmp/re.pl 'foo $1 bar'
var: foo middle bar
$ perl -T /tmp/re.pl 'foo $1 bar'
Insecure dependency in eval while running with -T switch at /tmp/re.pl line 10.
ただし、より慎重な手法は、正気で、安全で、安全で、汚染に失敗しません。(安心してください、それが発行する文字列はまだ汚染されているので、セキュリティを失うことはありません。)
他の人が示唆しているように、次を使用できます。
my $find = 'start (.*) end';
my $replace = 'foo $1 bar'; # 'foo \1 bar' is an error.
my $var = "start middle end";
$var =~ s/$find/$replace/ee;
上記は次の略です。
my $find = 'start (.*) end';
my $replace = 'foo $1 bar';
my $var = "start middle end";
$var =~ s/$find/ eval($replace) /e;
使用されているという事実を隠さないので、私は最初よりも 2 番目を好みeval(EXPR)
ます。ただし、上記のサイレンス エラーは両方とも発生するため、次のほうが適切です。
my $find = 'start (.*) end';
my $replace = 'foo $1 bar';
my $var = "start middle end";
$var =~ s/$find/ my $r = eval($replace); die $@ if $@; $r /e;
しかし、ご覧のとおり、上記のすべてが任意の Perl コードの実行を許可しています。以下ははるかに安全です。
use String::Substitution qw( sub_modify );
my $find = 'start (.*) end';
my $replace = 'foo $1 bar';
my $var = "start middle end";
sub_modify($var, $find, $replace);
# perl -de 0
$match="hi(.*)"
$sub='$1'
$res="hi1234"
$res =~ s/$match/$sub/gee
p $res
1234
ただし、注意してください。これにより、正規表現の最後にeval
それぞれ 1 つずつ、2 つのレイヤーが発生します。e
Perlでの置換側での変数の使用に関するこの以前のSO投稿を参照してください。受け入れられた答えと反論s///
の答えの両方を見てください。
あなたがやろうとしていることは、右側の弦でs///ee
ダブルを実行するフォームで可能です。その他の例については、演算子のようなperlopquoteeval
を参照してください。
のセキュリティ上の問題がeval
あり、これは汚染モードでは機能しないことに注意してください。
私は次のようなものを提案します:
$text =~ m{(.*)$find(.*)};
$text = $1 . $replace . $2;
かなり読みやすく、安全なようです。複数の交換が必要な場合、それは簡単です:
while ($text =~ m{(.*)$find(.*)}){
$text = $1 . $replace . $2;
}
#!/usr/bin/perl
$sub = "\\1";
$str = "hi1234";
$res = $str;
$match = "hi(.*)";
$res =~ s/$match/$1/g;
print $res
これで「1234」になりました。
あなたが何を達成しようとしているのかはわかりません。しかし、多分あなたはこれを使うことができます:
$var =~ s/^start/foo/;
$var =~ s/end$/bar/;
つまり、真ん中をそのままにして、開始と終了を置き換えます。