简体   繁体   中英

Perl regex replacement string special variable

I'm aware of the match, prematch, and postmatch predefined variables. I'm wondering if there is something similar for the evaluated replacement part of the s/// operator.

This would be particularly useful in dynamic expressions so they don't have to be evaluated a 2nd time.

For example, I currently have %regexs which is a hash of various search and replace strings.

Here's a snippet:

while (<>) {
  foreach my $key (keys %regexs) {   
    while (s/$regexs{$key}{'search'}/$regexs{$key}{'replace'}/ee) { 
      # Here I want to do something with just the replaced part 
      # without reevaluating.
    } 
  }
  print;
}

Is there a convenient way to do it? Perl seems to have so many convenient shortcuts, and it seems like a waste to have to evaluate twice (which appears to be the alternative).

EDIT: I just wanted to give an example: $regexs{$key}{'replace'} might be the string '"$2$1"' thus swapping the positions of some text in the string $regexs{$key}{'search'} which might be '(foo)(bar)' - thus resulting in "barfoo". The second evaluation that I'm trying to avoid is the output of $regexs{$key}{'replace'}.

Instead of using string eval (which I assume is what's going on with s///ee ), you could define code references to do the work. Those code references can then return the value of the replacement text. For example:

use strict;
use warnings;

my %regex = (
    digits  => sub {
        my $r;
        return unless $_[0] =~ s/(\d)(\d)_/$r = $2.$1/e;
        return $r;
    },
);

while (<DATA>){
    for my $k (keys %regex){
        while ( my $replacement_text = $regex{$k}->($_) ){
            print $replacement_text, "\n";
        }
    }
    print;
}

__END__
12_ab_78_gh_
34_cd_78_yz_

I'm pretty sure there isn't any direct way to do what you're asking, but that doesn't mean it's impossible. How about this?

{
  my $capture;
  sub capture {
    $capture = $_[0] if @_;
    $capture;
  }
}

while (s<$regexes{$key}{search}>
        <"capture('" . $regexes{$key}{replace}) . "')">eeg) {
  my $replacement = capture();
  #...
}

Well, except to do it really properly you'd have to shoehorn a little more code in there to make the value in the hash safe inside a singlequotish string (backslash singlequotes and backslashes).

If you do the second eval manually you can store the result yourself.

my $store;
s{$search}{ $store = eval $replace }e;

why not assign to local vars before:

my $replace = $regexs{$key}{'replace'};

now your evaluating once.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM