Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace a string when two strings exist in one regex in Perl

Tags:

regex

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. Like so:

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

(I imagine the .*MACRO2 part of this expression is unnecessary, now that I think about it) Edit. A less stupid version of the above based on feedback so far:

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

What I am trying to figure out is how to do it with just a regex. Here is one attempt:

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

I think I am having some fundamental confusion about how a lookahead operator can be both an "anchor" and "non-consuming" at the same time. If I think about ?= as an anchor, it makes sense to me that the above doesn't work. But that would seem to contradict "non-consuming".

Can anyone define what is meant by non-consuming and show me a regex that would produce the desired results?

like image 447
zzxyz Avatar asked Oct 18 '22 07:10

zzxyz


1 Answers

First, let's get the actual solution out there:

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

Now, let's look at your peculiar request. As a single substitution, it would look something like the following:

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

Ignoring the fact that this doesn't work because variable-width lookbehinds aren't supported, this is incredibly inefficient. While the time required by the first solution I presented is bound by a factor of the size of the file, the time required by this solution is bound by a factor of the size of the file times a factor of the number of instances of MACRO2!

like image 149
ikegami Avatar answered Oct 21 '22 02:10

ikegami