Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Computed regular expression replacement in Perl

Tags:

regex

perl

I want to do a global regex replace, where the replacement is conditional upon some logic that can't be put in a regular expression. For example:

while ( $var =~ /<IF OPERATOR="(.+?)" VALUE="(.+?)"\/>/g ) {
    my $operator = $1;
    my $value = $2;

    if ( $operator eq 'true' && $hash{ $value } ) {
        # replace the entire <IF/>
    }
    if ( $operator eq 'false' && ! $hash{ $value } ) {
        # replace the entire <IF/>
    }
}

How do I do the # replace bit? Thanks for any advice.

like image 739
David Avatar asked Aug 24 '26 15:08

David


2 Answers

Your refusal to give any real data for this question, or to describe what changes you want, makes it very difficult to demonstrate the workability of a solution.

However it looks like you need an executable replacement, which has the /e modifier.

Take a look at this code. I have added another pair of parentheses to the regex so that the entire pattern is captured as well as the two attributes. The actual replacement string is put into $replacement and returned by the block.

$string =~ s{(<IF OPERATOR="([^"]+)" VALUE="([^"]+)"/>)}{

    my $replacement = $1;
    my $operator    = $2;
    my $value       = $3;

    if ( $operator eq 'true' and $hash{$value} ) {
      $replacement = qq{<if state1="yes"/>};
    }
    elsif ( $operator eq 'false' and not $hash{$value} ) {
      $replacement = qq{<if state1="no"/>};
    }

    $replacement;
}eg;
like image 91
Borodin Avatar answered Aug 26 '26 20:08

Borodin


A lot of logic can be placed in regular expressions. For instance, there are conditional regular expressions, and you can execute Perl code in a regexp.

If you don't want to complicate the regexp, you can extract the offsets of the matches first, then splice them out with substr EXPR, OFFSET, LENGTH, ''.

But for the fun of using regexps, with named backreferences and s///e (evaluate the replacement), here is the code:

#!/usr/bin/perl -w
use strict;

my %hash = (
  foo => 1,
  bar => 0
);

my $var = '
<IF OPERATOR="true" VALUE="foo"/>
<IF OPERATOR="true" VALUE="bar"/>
<IF OPERATOR="false" VALUE="foo"/>
<IF OPERATOR="false" VALUE="bar"/>
';

$var =~
  s`(<IF\s+OPERATOR="(?<operator>.+?)"\s+VALUE="(?<value>.+?)"/>)
   `$+{operator} eq 'true' && $hash{ $+{value} } || $+{operator} eq 'false' && !$hash{ $+{value} }? 'replacement' : $1
   `xeg;

print $var;
like image 38
Dan Dascalescu Avatar answered Aug 26 '26 19:08

Dan Dascalescu



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!