Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Re: Regexp substitution using variables

by MikeTaylor (Acolyte)
on Nov 25, 2020 at 23:33 UTC ( [id://11124241]=note: print w/replies, xml ) Need Help??


in reply to Regexp substitution using variables

Here is what I am doing at the moment:
$replacement =~ s/\\/\\\\/g; eval "\$res =~ s/$pattern/$replacement/$flags";
It's working, and crucially supports back-references — unlike the $res =~ s/(?$flags:$pattern)/$replacement/ solution.

Of course, the use of eval gives me the heebie-jeebies; but I'm not going to lose too much sleep as we already need to trust the people who write the configuration files that will contain the values used in the eval.

Replies are listed 'Best First'.
Re^2: Regexp substitution using variables
by AnomalousMonk (Archbishop) on Nov 26, 2020 at 09:50 UTC

    Partly in answer to choroba's challenge, here's an approach that works with forward/backslashes, escape sequences and capture variables in replacement strings. Whether it will answer your needs is another question. A fixup step for forward slashes is necessary. Works under Perl versions 5.8.9 and 5.30.3.

    Win8 Strawberry 5.8.9.5 (32) Thu 11/26/2020 4:08:05 C:\@Work\Perl\monks >perl use strict; use warnings; my $pattern = '(\\\\tEs/Ti//N\x67\\\)'; my $replacement = '\\\Fr/es//h\\\\ \U$1'; my $flags = 'i'; # $got_g is true if /g modifier present in flags. # ($flags, my $got_g) = sanitize_flags_detect_g($flags); fixup_forward_slashes($pattern, $replacement); my $value = 'My \Tes/ti//ng\ Text'; print "replacement '$replacement' \n"; my $eval_string = "\$value =~ s/$pattern/$replacement/$flags"; print "eval_string '$eval_string' \n"; eval $eval_string; print "eval err '$@' \n"; print "output '$value' \n"; sub fixup_forward_slashes { s{/}'\/'g for @_; } ^Z replacement '\\Fr\/es\/\/h\\ \U$1' eval_string '$value =~ s/(\\tEs\/Ti\/\/N\x67\\)/\\Fr\/es\/\/h\\ \U$1/i +' eval err '' output 'My \Fr/es//h\ \TES/TI//NG\ Text'
    It's awkward that a \ single literal backslash in the input/output string must be represented by a \\ double backslash in the substitution and by \\\ triple or \\\\\ quadruple backslashes in the single-quoted pattern/replacement strings, but that's single/double-quotish backslash handling for ya. If the pattern/replacement strings were taken from a file, it would be possible to just use double backslashes.


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

Re^2: Regexp substitution using variables
by choroba (Cardinal) on Nov 26, 2020 at 07:13 UTC
    > It's working

    OK, now try to include a slash into the pattern or replacement.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re^2: Regexp substitution using variables
by hippo (Bishop) on Nov 26, 2020 at 09:50 UTC
    we already need to trust the people who write the configuration files that will contain the values used in the eval.

    Beware Hanlon's Razor. Are you trusting them to be competent or just benign? In your shoes I would be untainting their input very conservatively.


    🦛

Re^2: Regexp substitution using variables
by Bod (Parson) on Nov 26, 2020 at 01:11 UTC

    It's working, and crucially supports back-references

    That's interesting as I cannot get this to support back-references...this is very similar to my initial attempt. So I have attempted to replicate it:

    use strict; my $pattern = '(testing)'; my $replacement = 'New \1'; my $flags = 'i'; my $value = 'My Testing Text'; $replacement =~ s/\\/\\\\/g; eval "\$value =~ s/$pattern/$replacement/$flags"; print "$value\n";
    This prints
    My New \1 Text
    It doesn't substitute the capture.

      The OPed sort of problem is tricky, but for this specific iteration:

      Win8 Strawberry 5.8.9.5 (32) Wed 11/25/2020 22:12:13 C:\@Work\Perl\monks >perl use strict; use warnings; my $pattern = '(testing)'; my $replacement = 'New \U$1'; my $flags = 'i'; my $value = 'My Testing Text'; ### $replacement =~ s/\\/\\\\/g; print "replacement '$replacement' \n"; eval "\$value =~ s/$pattern/$replacement/$flags"; print "$value\n"; ^Z replacement 'New \U$1' My New TESTING Text
      (An escaped backreference \1 is not kosher in a replacement string anyway; it should be in $1 form.)

      Update: Here's a version of the example code that better illustrates the process of building the evaluation string:

      Win8 Strawberry 5.8.9.5 (32) Wed 11/25/2020 22:45:44 C:\@Work\Perl\monks >perl use strict; use warnings; my $pattern = '(testing)'; my $replacement = 'New \U$1'; my $flags = 'i'; my $value = 'My Testing Text'; print "replacement '$replacement' \n"; my $eval_string = "\$value =~ s/$pattern/$replacement/$flags"; print "eval_string '$eval_string' \n"; eval $eval_string; print "$value\n"; ^Z replacement 'New \U$1' eval_string '$value =~ s/(testing)/New \U$1/i' My New TESTING Text


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

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11124241]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (2)
As of 2024-04-26 00:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found