Je voudrais faire ce qui suit:
$find="start (.*) end";
$replace="foo \1 bar";
$var = "start middle end";
$var =~ s/$find/$replace/;
Je m'attendrais à ce que $ var contienne "foo middle bar", mais cela ne fonctionne pas. Ni:
$replace='foo \1 bar';
D'une manière ou d'une autre, il me manque quelque chose concernant l'évasion.
J'ai corrigé le 's' manquant
Du côté du remplacement, vous devez utiliser $ 1, pas\1.
Et vous ne pouvez faire que ce que vous voulez en faisant remplacer une expression évaluable qui donne le résultat souhaité et en demandant à s /// de l’évaluer avec le modificateur/ee comme suit:
$find="start (.*) end";
$replace='"foo $1 bar"';
$var = "start middle end";
$var =~ s/$find/$replace/ee;
print "var: $var\n";
Pour voir pourquoi "" et double/e sont nécessaires, voyez l'effet de la double évaluation ici:
$ Perl
$foo = "middle";
$replace='"foo $foo bar"';
print eval('$replace'), "\n";
print eval(eval('$replace')), "\n";
__END__
"foo $foo bar"
foo middle bar
Deparse nous dit que c'est ce qui est en train d'être exécuté:
$find = 'start (.*) end';
$replace = "foo \cA bar";
$var = 'start middle end';
$var =~ s/$find/$replace/;
Cependant,
/$find/foo \1 bar/
Est interprété comme:
$var =~ s/$find/foo $1 bar/;
Malheureusement, il semble qu'il n'y ait pas de moyen facile de le faire.
Vous pouvez le faire avec une chaîne eval, mais c'est dangereux.
La solution la plus saine qui a fonctionné pour moi était la suivante:
$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;
Comme je l'ai dit dans ma réponse, j'évite les évaluations pour une raison.
$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";
ce code fait exactement ce que vous pensez qu'il fait.
Si votre chaîne de substitution se trouve dans une application Web, vous venez d'ouvrir la porte à l'exécution de code arbitraire.
Bon travail.
En outre, il WON'T / travailler avec les souillures allumé pour cette raison même.
$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.
Cependant, la technique la plus prudente est la suivante: saine et sauve, et ne manque pas de teinture (Soyez assuré que la chaîne qu'il émet est toujours souillée, vous ne perdez donc aucune sécurité.)
# Perl -de 0
$match="hi(.*)"
$sub='$1'
$res="hi1234"
$res =~ s/$match/$sub/gee
p $res
1234
Soyez prudent, cependant. Cela provoque deux couches de eval
, une pour chaque e
à la fin de la regex:
Comme d'autres l'ont suggéré, vous pouvez utiliser les éléments suivants:
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;
Ce qui précède est l'abréviation de:
my $find = 'start (.*) end';
my $replace = 'foo $1 bar';
my $var = "start middle end";
$var =~ s/$find/ eval($replace) /e;
Je préfère le second au premier car il ne cache pas le fait que eval(EXPR)
est utilisé. Cependant, les deux erreurs de silence ci-dessus, il serait donc préférable de:
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;
Mais comme vous pouvez le constater, tout ce qui précède permet l'exécution de code Perl arbitraire. Ce qui suit serait beaucoup plus sûr:
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);
Voir THIS précédent SO post sur l'utilisation d'une variable du côté de remplacement de s///
in Perl. Regardez à la fois la réponse acceptée et la réfutation réponse.
Ce que vous essayez de faire est possible avec le formulaire s///ee
qui exécute une double eval
sur la chaîne de droite. Voir perlop cite comme des opérateurs pour plus d'exemples.
Soyez averti qu'il existe des impilcations de sécurité de eval
et que cela ne fonctionnera pas en mode altéré.
Je suggérerais quelque chose comme:
$text =~ m{(.*)$find(.*)};
$text = $1 . $replace . $2;
Il est assez lisible et semble être en sécurité. Si plusieurs remplacements sont nécessaires, c'est facile:
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
Cela m'a valu le «1234».