Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python RegEx: how to replace each match individually

I have a string s, a pattern p and a replacement r, i need to get the list of strings in which only one match with p has been replaced with r.

Example:

s = 'AbcAbAcc'
p = 'A'
r = '_'

// Output:
['_bcAbAcc', 'Abc_bAcc', 'AbcAb_cc']

I have tried with re.finditer(p, s) but i couldn't figure out how to replace each match with r.

like image 657
sephiroth Avatar asked Oct 21 '25 03:10

sephiroth


2 Answers

You can replace them manually after finding all the matches:

[s[:m.start()] + r + s[m.end():] for m in re.finditer(p,s)]

The result is:

['_bcAbAcc', 'Abc_bAcc', 'AbcAb_cc']

How does it work?

  • re.finditer(p,s) will find all matches (each will be a re.Match object)
  • the re.Match objects have start() and end() method which return the location of the match
  • you can replace the part of string between begin and end using this code: s[:begin] + replacement + s[end:]
like image 137
zvone Avatar answered Oct 23 '25 20:10

zvone


You don't need regex for this, it's as simple as

[s[:i]+r+s[i+1:] for i,c in enumerate(s) if c==p]

Full code: See it working here

s = 'AbcAbAcc'
p = 'A'
r = '_'

x = [s[:i]+r+s[i+1:] for i,c in enumerate(s) if c==p]
print(x)

Outputs:

['_bcAbAcc', 'Abc_bAcc', 'AbcAb_cc']

As mentioned, this only works on one character, for anything longer than one character or requiring a regex, use zvone's answer.

For a performance comparison between mine and zvone's answer (plus a third method of doing this without regex), see here or test it yourself with the code below:

import timeit,re

s = 'AbcAbAcc'
p = 'A'
r = '_'

def x1():
    return [s[:i]+r+s[i+1:] for i,c in enumerate(s) if c==p]

def x2():
    return [s[:i]+r+s[i+1:] for i in range(len(s)) if s[i]==p]

def x3():
    return [s[:m.start()] + r + s[m.end():] for m in re.finditer(p,s)]

print(x1())
print(timeit.timeit(x1, number=100000))
print(x2())
print(timeit.timeit(x2, number=100000))
print(x3())
print(timeit.timeit(x3, number=100000))
like image 27
ctwheels Avatar answered Oct 23 '25 21:10

ctwheels



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!