luc.bouge has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks

I have tried the following replacement script, which does not work.

$ more replace.pl #!/usr/bin/perl -w -pi.orig s/(a)(b)/$1{$2}/g; $ more test.txt ab $ ./replace.pl test.txt Use of uninitialized value within %1 in substitution iterator at ./rep +lace.pl line 3, <> line 1. $ more test.txt (an empty line)
However, it works fine with an additional escaping backslash before the left brace: s/(a)(b)/$1\{$2}/g;. I suspect that $1{$2} is recognized as addressing an associative array, but I could not find any mention in the documentation about such an expansion in the substitution part of a RE. Could somebody tell me? Regards, Luc.

Replies are listed 'Best First'.
Re: Brace in the replacement part of a regular expression substitution
by haukex (Archbishop) on Oct 22, 2018 at 07:32 UTC
    I suspect that $1{$2} is recognized as addressing an associative array, but I could not find any mention in the documentation about such an expansion in the substitution part of a RE.

    See Quote and Quote like Operators:

    ... In the following table, a {} represents any pair of delimiters you choose.
    Customary Generic Meaning Interpolates ... s{}{} Substitution yes* ... * unless the delimiter is ''.

    Where "interpolates" means the same thing as what happens to strings in double quotes, like "$hash{$key}", or, in your case, "$1{$2}". The error message gives you a hint: "Use of uninitialized value within %1 in substitution iterator" - so yes, $1{$2} means the same as $x{$y}, that is, access the hash %1 and fetch the key named by the string stored in $2. Your solution of adding the backslash is fine.

Re: Brace in the replacement part of a regular expression substitution
by kcott (Archbishop) on Oct 22, 2018 at 07:52 UTC

    G'day Luc,

    Welcome to the Monastery.

    The documentation you're probably looking for is "perlop: Quote and Quote-like Operators". Note the "Interpolates" column in the table at the start of that section.

    In the next main section, perlop: Regexp Quote-Like Operators", you'll see s/PATTERN/REPLACEMENT/... (you'll need to scroll to the end of that section). That simply refers to "replacement text". I can't see any further mention of interpolating here; although, as indicated via my first link, it does occur.

    Note: I'm using a standard alias of mine in all the examples:

    $ alias perle alias perle='perl -Mstrict -Mwarnings -Mautodie=:all -MCarp::Always -E +'

    Just as you can interpolate hash elements in an interpolated string:

    $ perle 'my %x = qw{0 a 1 b 2 c}; say "$x{0}$x{1}$x{2}"' abc

    You can do the same in s/// interpolated replacement text:

    $ perle 'my %x = qw{0 a 1 b 2 c}; say "012" =~ s/([012])/$x{$1}/gr' abc

    The same applies to array elements in an interpolated string:

    $ perle 'my @x = qw{a b c}; say "$x[0]$x[1]$x[2]"' abc

    And, equivalently, in s/// interpolated replacement text:

    $ perle 'my @x = qw{a b c}; say "012" =~ s/([012])/$x[$1]/gr' abc

    This has actually been around for a long time. I use it often and, as it's so ingrained, it took a while to locate the doco.

    Here's a very quick-and-dirty example of usage to prepare raw text for HTML:

    $ perle 'my %ent = qw{& &amp; < &lt; > &gt;}; say "... < & > ..." =~ s +/([&><])/$ent{$1}/gr' ... &lt; &amp; &gt; ...

    — Ken

Re: Brace in the replacement part of a regular expression substitution
by AnomalousMonk (Archbishop) on Oct 22, 2018 at 20:16 UTC

    Further to kcott's post:

    $ perle 'my %ent = qw{& &amp; < &lt; > &gt;}; say "... < & > ..." =~ s/([&><])/$ent{$1}/gr'
    ... &lt; &amp; &gt; ...

    luc.bouge:   Also see haukex's article for a very useful technique to dynamically prepare a search (sub-)regex from a "translation" hash like %ent.


    Give a man a fish:  <%-{-{-{-<