Replace a string when two strings exist in the same regex in Perl

Given the following input

$ cat pre stuff MACRO1 stuff MACRO2 stuff MACRO2 stuff MACRO1 stuff MACRO2 stuff 

I want to replace MACRO2 (with MACRO3) if MACRO1 also exists. For instance:

 $ perl -ne '/(?=.*MACRO1).*MACRO2/ ? print s/MACRO2/MACRO3/gr : print' pre stuff MACRO1 stuff MACRO3 stuff MACRO3 stuff MACRO1 stuff MACRO2 stuff 

(I suppose .*MACRO2 part of this expression is not needed, now that I think about it) Edit. Less silly version above based on feedback:

 $ perl -ne '/MACRO1/ ? print s/MACRO2/MACRO3/gr : print' pre 

What I'm trying to figure out is how to do this with regex only. Here is one try:

 $ perl -ne 'print s/(?=.*MACRO1)(?=.*MACRO2)MACRO2/MACRO3/gr' pre stuff MACRO1 stuff MACRO2 stuff MACRO3 stuff MACRO1 stuff MACRO2 stuff 

I think that I have a fundamental confusion as to how the gaze operator can be both an โ€œanchorโ€ and a โ€œnon-consumingโ€ one. If I think of ?= As an anchor, it seems to me that the above does not work. But this, it would seem, contradicts the "not consuming".

Can someone define what is meant by non-consumer and show me a regular expression that will give the desired results?

+5
source share
2 answers

First, let's get the actual solution:

 perl -pe's/MACRO2/MACRO3/g if /MACRO1/' 

Now look at your special request. As one substitution, it would look something like this:

 perl -pe's/MACRO2(?:(?<=MACRO1.*)|(?=.*MACRO1))/MACRO3/g' 

Ignoring the fact that this does not work because variable lookbehind widths are not supported, it is incredibly inefficient. Although the time required by the first solution I presented is related to the file size ratio, the time required by this solution is related to the file size coefficient times the number of MACRO2 instances!

+3
source

Then always:

 $rec =~ s/^(.*)MACRO1(.*)MACRO2(.*)$/\1MACRO1\2MACRO3\3/; 

Ok, for the comment (what if MACRO2 comes first):

 sub foo { my ($x) = @_; $x =~ s/2/3/; return $x; } 

Then:

 $s3 =~ s/^(.*)((MACRO1(.*)MACRO2)|(MACRO2(.*)MACRO1))(.*)$/$1.($3?foo($3):foo($5))/e; 

Of course, this requires a function (I called it foo).

It can be done without a function, nesting match / replace in a replacement template to do the same, but I was getting a lot of syntactic sadness from Perl (I'm sure by my mistake).

0
source

Source: https://habr.com/ru/post/1271008/


All Articles