change only the nth occurrence of a pattern in a string

Tim Chase python.list at tim.thechases.com
Wed Dec 31 16:48:29 CET 2008


> I would like to change only the nth occurence of a pattern in 
> a string. The problem with "replace" method of strings, and
> "re.sub" is that  we can only define the number of occurrences
> to change from the  first one.
> 
>>>> v="coucou"
>>>> v.replace("o","i",2)
> 'ciuciu'
>>>> import re
>>>> re.sub( "o", "i", v,2)
> 'ciuciu'
>>>> re.sub( "o", "i", v,1)
> 'ciucou'
> 
> What is the best way to change only the nth occurence
> (occurrence number n)?

Well, there are multiple ways of doing this, including munging 
the regexp to skip over the first instances of a match. 
Something like the following untested:

   re.sub("((?:[^o]*o){2})o", r"\1i", s)

However, for a more generic solution, you could use something like

   import re
   class Nth(object):
     def __init__(self, n_min, n_max, replacement):
       #assert n_min <= n_max, \
       #  "Hey, look, I don't know what I'm doing!"
       if n_max > n_min:
	# don't be a dope
         n_min, n_max = n_max, n_min
       self.n_min = n_min
       self.n_max = n_max
       self.replacement = replacement
       self.calls = 0
     def __call__(self, matchobj):
       self.calls += 1
       if self.n_min <= self.calls <= self.n_max:
         return self.replacement
       return matchobj.group(0)

   s = 'coucoucoucou'
   print "Initial:"
   print s
   print "Just positions 3-4:"
   print re.sub('o', Nth(3,4,'i'), s)
   for params in [
       (1, 1, 'i'),  # just the 1st
       (1, 2, 'i'),  # 1-2
       (2, 2, 'i'),  # just the 2nd
       (2, 3, 'i'),  # 2-3
       (2, 4, 'i'),  # 2-4
       (4, 4, 'i'),  # just the 4th
       ]:
     print "Nth(%i, %i, %s)" % params
     print re.sub('o', Nth(*params), s)

> Why this default behavior?

Can't answer that one, but with so many easy solutions, it's not 
been a big concern of mine.

-tkc








More information about the Python-list mailing list