Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I replace all occurrences of certain characters with their predecessors?

Tags:

regex

perl

$s = "bla..bla";
$s =~ s/([^%])\./$1/g;

I think it should replace all occurrences of . that is not after % with the character that is before ..

But $s is then: bla.bla, but it should be blabla. Where is the problem? I know I can use quantifiers, but I need do it this way.

like image 693
Krab Avatar asked Feb 20 '13 17:02

Krab


2 Answers

When a global regular expression is searching a string it will not find overlapping matches.

The first match in your string will be a., which is replaced with a. When the regex engine resumes searching it starts at the next . so it sees .bla as the rest of the string, and your regex requires a character to match before the . so it cannot match again.

Instead, use a negative lookbehind to perform the assertion that the previous character is not %:

$s =~ s/(?<!%)\.//g;

Note that if you use a positive lookbehind like (?<=[^%]), you will not replace the . if it is the first character in the string.

like image 81
Andrew Clark Avatar answered Oct 18 '22 03:10

Andrew Clark


The problem is that even with the /g flag, each substitution starts looking where the previous one left off. You're trying to replace a. with a and then a. with a, but the second replacement doesn't happen because the a has already been "swallowed" by the previous replacement.

One fix is to use a zero-width lookbehind assertion:

$s =~ s/(?<=[^%])\.//g;

which will remove any . that is not the first character in the string, and that is not preceded by %.

But you might actually want this:

$s =~ s/(?<!%)\.//g;

which will remove any . that is not preceded by %, even if it is the first character in the string.

like image 6
ruakh Avatar answered Oct 18 '22 02:10

ruakh