Perl : utiliser des références arrière dans une variable de chaîne de remplacement

Aug 21 2020

J'effectue une substitution de chaîne en Perl, mais j'ai à la fois le modèle et les chaînes de remplacement stockées en tant que variables scalaires en dehors des opérateurs d'expression régulière. Le problème est que je veux que la chaîne de remplacement puisse utiliser des références arrière.

J'espère que le code ci-dessous illustrera la question plus clairement.

my $pattern = 'I have a pet (\w+).'; my $replacement = 'My pet $1 is a good boy.'; my $original_string = 'I have a pet dog.';

# Not Working
my $new_string = $original_string =~ s/$pattern/$replacement/r;

# Working
#my $new_string = $original_string =~ s/$pattern/My pet $1 is a good boy./r;

# Expected: "My pet dog is a good boy."
# Actual: "My pet $1 is a good boy." print "$new_string\n";

Réponses

5 ikegami Aug 21 2020 at 12:23
s/$pattern/My pet $1 is a good boy./

est l'abréviation de

s/$pattern/ "My pet $1 is a good boy." /e

L'expression de remplacement ( "My pet $1 is a good boy.") est un littéral de chaîne qui interpole $1.


Cela signifie que

s/$pattern/$replacement/

est l'abréviation de

s/$pattern/ "$replacement" /e

L'expression de remplacement ( "$replacement") est un littéral de chaîne qui interpole $replacement(pas $1).


Bien que cela puisse vous gêner, c'est une bonne chose que vous n'ayez perlpas l'habitude d'exécuter le contenu des variables en tant que code Perl. :)

Vous pouvez utiliser gsub_copyfrom String :: Substitution pour résoudre votre problème.

use String::Subtitution qw( gsub_copy );

my $pattern         = 'I have a pet (\w+)\.';
my $replacement = 'My pet $1 is a good boy.';
my $original_string = 'I have a pet dog.'; my $new_string = gsub_copy($original_string, $pattern, $replacement);
4 zdim Aug 21 2020 at 09:54

Cela $1dans la chaîne de remplacement n'est que des caractères successifs $et 1, et pour en faire une variable pour la première capture, vous devrez passer par de mauvais cerceaux.

Que diriez-vous d'une alternative

my string = q(a pet dog);

my $pattern = qr/a pet (\w+)/; my $new = $string =~ s/$pattern/ repl($1) /er; sub repl { my ($capture) = @_;
    return "$capture is a good boy";
}

où le sous est vraiment juste

sub repl { "$_[0] is a good boy" }

C'est un peu plus mais c'est plus capable et flexible.


Ou, comme il s'avère par la réponse d'ikegami, utilisez String :: Substitution qui résume toutes les « subtilités » impliquées en un seul appel