Replace the nth occurrence of a substring in a string

I want to replace the nth occurrence of a substring in a string.

There must be something equivalent to what I want to do is

mystring.replace("substring", 2nd)

What is the easiest and most pythonic way to achieve this?

Why not duplicate: I don’t want to use a regular expression for this approach, and most of the answers to similar questions that I found are just cleaning up regular expressions or a really complicated function. I really want a simpler solution than a regular one.

+7
source share
5 answers

I use a simple function that lists all occurrences, selects the nth position, and uses it to split the original string into two substrings. Then it replaces the first occurrence in the second substring and appends the substrings back to the new line:

 import re def replacenth(string, sub, wanted, n) where = [m.start() for m in re.finditer(sub, string)][n-1] before = string[:where] after = string[where:] after = after.replace(sub, wanted, 1) newString = before + after print newString 

For these variables:

 string = 'ababababababababab' sub = 'ab' wanted = 'CD' n = 5 

outputs:

 ababababCDabababab 

Notes:

The where variable is actually a list of match positions at which you select the nth. But the list item index starts at 0 normally, not 1 . Therefore, there is an index n-1 , and n is the actual nth substring. My example finds the 5th line. If you use index n and want to find the 5th position, you need n be 4 . Usually you use a function that generates our n .

This should be the easiest way, but maybe this is not the Pythonic way, because the construction of the where variable requires importing the re library. Maybe someone will find an even more pythonic path.

Sources and some links optionally:

0
source

You can use the while loop with str.find to find the nth occurrence, if it exists, and use this position to create a new line:

 def nth_repl(s, sub, repl, nth): find = s.find(sub) # if find is not p1 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 != nth: # find + 1 means we start at the last match start index + 1 find = s.find(sub, find + 1) i += 1 # if i is equal to nth we found nth matches so replace if i == nth: 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' 
+8
source

I came up with below, which also discusses options for replacing all the "old" lines left or right. Naturally, there is no way to replace all occurrences, since the standard str.replace works fine.

 def nth_replace(string, old, new, n=1, option='only nth'): """ This function replaces occurrences of string 'old' with string 'new'. There are three types of replacement of string 'old': 1) 'only nth' replaces only nth occurrence (default). 2) 'all left' replaces nth occurrence and all occurrences to the left. 3) 'all right' replaces nth occurrence and all occurrences to the right. """ if option == 'only nth': left_join = old right_join = old elif option == 'all left': left_join = new right_join = old elif option == 'all right': left_join = old right_join = new else: print("Invalid option. Please choose from: 'only nth' (default), 'all left' or 'all right'") return None groups = string.split(old) nth_split = [left_join.join(groups[:n]), right_join.join(groups[n:])] return new.join(nth_split) 
+2
source

The last answer is almost perfect - only one correction:

  def replacenth(string, sub, wanted, n): where = [m.start() for m in re.finditer(sub, string)][n - 1] before = string[:where] after = string[where:] after = after.replace(sub, wanted) newString = before + after return newString 

After changing the line after this replacement, you must save this variable again. Thanks for the great solution!

0
source

I had a similar need, i.e. Find IP addresses in logs and selectively replace only src IP or dst IP. So I reached in a pythonic manner;

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

Source: https://habr.com/ru/post/1241845/


All Articles