I want to replace the n\'th occurrence of a substring in a string.
There\'s got to be something equivalent to what I WANT to do which is
mystring.repl
I've tweaked @aleskva's answer to better work with regex and wildcards:
import re
def replacenth(string, sub, wanted, n):
pattern = re.compile(sub)
where = [m for m in pattern.finditer(string)][n-1]
before = string[:where.start()]
after = string[where.end():]
newString = before + wanted + after
return newString
replacenth('abdsahd124njhdasjk124ndjaksnd124ndjkas', '1.*?n', '15', 1)
This gives abdsahd15jhdasjk124ndjaksnd124ndjkas
. Note the use of ?
to make the query non-greedy.
I realise that the question explicitly states that they didn't want to use regex, however it may be useful to be able to use wildcards in a clear fashion (hence my answer).
You can use a while loop with str.find
to find the nth occurrence if it exists and use that position to create the new string:
def nth_repl(s, sub, repl, n):
find = s.find(sub)
# If find is not -1 we have found at least one match for the substring
i = find != -1
# loop util we find the nth or we find no match
while find != -1 and i != n:
# find + 1 means we start searching from after the last match
find = s.find(sub, find + 1)
i += 1
# If i is equal to n we found nth match so replace
if i == n:
return s[:find] + repl + s[find+len(sub):]
return s
Example:
In [14]: s = "foobarfoofoobarbar"
In [15]: nth_repl(s, "bar","replaced",3)
Out[15]: 'foobarfoofoobarreplaced'
In [16]: nth_repl(s, "foo","replaced",3)
Out[16]: 'foobarfooreplacedbarbar'
In [17]: nth_repl(s, "foo","replaced",5)
Out[17]: 'foobarfoofoobarbar'
My two cents
a='01ab12ab23ab34ab45ab56ab67ab78ab89ab90';print('The original string: ', a)
sTar = 'ab';print('Look for: ', sTar)
n = 4; print('At occurence #:', n)
sSub = '***';print('Substitute with: ', sSub)
t = 0
for i in range(n):
t = a.find(sTar,t)
print(i+1, 'x occurence at', t)
if t != -1: t+=1
t-=1 #reset, get the correct location
yy = a[:t] + a[t:].replace(sTar, sSub, 1)
print('New string is:', yy)
Output
The original string: 01ab12ab23ab34ab45ab56ab67ab78ab89ab90
Look for: ab
At occurence #: 4
Substitute with: ***
1 x occurence at 2
2 x occurence at 6
3 x occurence at 10
4 x occurence at 14
New string is: 01ab12ab23ab34***45ab56ab67ab78ab89ab90
I had a similar need, i.e to find the IPs in logs and replace only src IP or dst IP field selectively. This is how i achieved in a pythonic way;
import re
mystr = '203.23.48.0 DENIED 302 449 800 1.1 302 http d.flashresultats.fr 10.111.103.202 GET GET - 188.92.40.78 '
src = '1.1.1.1'
replace_nth = lambda mystr, pattern, sub, n: re.sub(re.findall(pattern, mystr)[n - 1], sub, mystr)
result = replace_nth(mystr, '\S*\d+\.\d+\.\d+\.\d+\S*', src, 2)
print(result)