Replacing Only The Nth Instance of Character

Replace nth occurrence of substring in string

I use simple function, which lists all occurrences, picks the nth one's position and uses it to split original string into two substrings. Then it replaces first occurrence in the second substring and joins substrings back into the new string:

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 actually is a list of matches' positions, where you pick up the nth one. But list item index starts with 0 usually, not with 1. Therefore there is a n-1 index and n variable is the actual nth substring. My example finds 5th string. If you use n index and want to find 5th position, you'll need n to be 4. Which you use usually depends on the function, which generates our n.

This should be the simplest way, but maybe it isn't the most Pythonic way, because the where variable construction needs importing re library. Maybe somebody will find even more Pythonic way.

Sources and some links in addition:

  • where construction: How to find all occurrences of a substring?
  • string splitting: https://www.daniweb.com/programming/software-development/threads/452362/replace-nth-occurrence-of-any-sub-string-in-a-string
  • similar question: Find the nth occurrence of substring in a string

Replacing only the nth instance of character

To replace the first instance of a character I would recommend the use of the STUFF and CHARINDEX functions. STUFF inserts a string into another string. It deletes a specified length of characters in the first string at the start position and then inserts the second string into the first string at the start position.

DECLARE @str varchar(100) = '^1402 WSN NIAMLAB^teertS htimS 005'
SELECT STUFF(@str, CHARINDEX('^', @str), 1, '&')

Note that you could also use STUFF in a query as follows:

SELECT STUFF(<yourcolumn>, CHARINDEX('^', <yourcolumn>), 1, '&')
FROM <yourtable>

Replace Nth occurrence of a character in a string with something else

You can replace ((?:\d+, ){3}\d), with \1\n

You basically capture everything till fourth comma in group1 and comma separately and replace it with \1\n which replaces matched text with group1 text and newline, giving you the intended results.

Regex Demo

R Code demo

gsub("((?:\\d+, ){3}\\d),", "\\1\n", "1, 2, 3, 4, 5, 6, 7, 8, 9, 10")

Prints,

[1] "1, 2, 3, 4\n 5, 6, 7, 8\n 9, 10"

Edit:

To generalize above solution to any text, we can change \d to [^,]

New R code demo

gsub("((?:[^,]+, ){3}[^,]+),", "\\1\n", "1, 2, 3, 4, 5, 6, 7, 8, 9, 10")
gsub("((?:[^,]+, ){3}[^,]+),", "\\1\n", "a, bb, ccc, dddd, 500, 600, 700, 800, 900, 1000")

Output,

[1] "1, 2, 3, 4\n 5, 6, 7, 8\n 9, 10"
[1] "a, bb, ccc, dddd\n 500, 600, 700, 800\n 900, 1000"

stringr remove n-th occurence of a character

To remove the second occurrence only, you need to use

sub("(ab.*?)ab", "\\1", "abcdabef")

To remove the nth occurrence, use a limiting quantifier after the group where the only min value should be equal to n-1:

n <- 2
sub(paste0("((?:ab.*?){",n-1,"})ab"), "\\1", "abcdabef", perl=TRUE)

Note:

You need to use sub and not gsub since you only need a single replacement to be done.

Pattern details (when n=3):

  • ((?:ab.*?){2}) - Group 1 (\1): two occurrences of ab and any zero or more chars other than line break chars (since I am using perl=TRUE here, if you need multiple line matching support, add (?s) at the start or replace .*? with (?s:.*?)) as few as possible
  • ab - an ab

If you have arbitrary strings with special chars in them, you need to escape them:

regex.escape <- function(string) {
gsub("([][{}()+*^$|\\\\?.])", "\\\\\\1", string)
}

word <- "a+(b)"
word <- regex.escape(word)
text <- "a+(b)1___a+(b)2___a+(b)3___a+(b)4"
n <- 3 # Let's remove the 3rd occurrence of a+(b)
sub(paste0("((?:", word, ".*?){",n-1,"})", word), "\\1", text, perl=TRUE)
## => [1] "a+(b)1___a+(b)2___3___a+(b)4"

See the regex demo.

Python - replace every nth occurrence of string

The code you got from the previous question is a nice starting point, and only a minimal adaptation is required to have it change every nth occurence:

def nth_repl_all(s, sub, repl, nth):
find = s.find(sub)
# loop util we find no match
i = 1
while find != -1:
# if i is equal to nth we found nth matches so replace
if i == nth:
s = s[:find]+repl+s[find + len(sub):]
i = 0
# find + len(sub) + 1 means we start after the last match
find = s.find(sub, find + len(sub) + 1)
i += 1
return s

Replacing nth occurence of a string in MySQL

In MySQLv8.0 you can use REGEXP_REPLACE()

https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function_regexp-replace

REGEXP_REPLACE(expr, pat, repl[, pos[, occurrence[, match_type]]])

So if you want to start searching from position 1 and replace only the 2nd occurence of the match you can use 1,2 as the last two options:

UPDATE `table` SET `field`=REGEXP_REPLACE(`field`,'search_string','replacement_string',1, 2);

Note:There was a bug report for MySql Version: 8.0.11 that was fixed in 8.0.12.

https://bugs.mysql.com/bug.php?id=90870

Before using in production test that you have the right MySql version and it works for you.

Replace String in between nth and n+1 occurrence of a character in Java

The better way - using regex

String input = "abc_1234_01233456_DC";
Matcher matcher = Pattern.compile("(_([^_]+)){2}").matcher(input);//{2} - number of occurrence
String result = matcher.find() ? new StringBuilder(input).replace(matcher.start(2), matcher.end(2), "78910").toString() : input; //abc_1234_78910_DC

That's it



Related Topics



Leave a reply



Submit