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





--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to