4

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.

2 Answers 2

5

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:]
Sign up to request clarification or add additional context in comments.

2 Comments

Suggest using m.start() instead of m.span()[0] and m.end() instead of m.span()[1].
@RootTwo: Absolutely. Thanks. I updated the answer.
1

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))

2 Comments

That's only true if p is always one character long, but for what i need p is going to be an actual pattern. But yes with the example I provided that's going to work perfectly!
Easy to extend to many characters long. x = [s[:m] + r + s[m+len(p):] for m in findall(s, p)]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.