HEY! -- replace multiple keywords (bit more complicated)

I posted a thread previously on replacements for a keyword, but the suggestions that were given were great but didnt do the job.... would love any more suggestions to crack the mystery!

the previous example i was given in my other thread was this...

>>> t = 'I love cheese; cheese is my favourite besides melted cheese.'
>>> t.replace ('cheese', 'shredded gorgonzola', 1)
>>>'I love shredded gorgonzola; cheese is my favourite besides shredded cheese.'

Awesome, solution but I want to add a bit more complication to the problem. This solution only replaces 1 keyword - the first 'cheese'. what if i want to change the next to 'cheese' to different words. i.e i want my result to be the following:

>>>'I love shredded gorgonzola; bree is my favourite besides camenbert.'

so although all the words are the same I want to change them to all different words... Hope that makes sense.

Thanks buddy's!!!! Hope we can figure this crazy problem out!!! PLEASE PLEASE please reply to this thread with any suggestions... even if it doesnt completely solve the problem... ideas on what could be involved in the solution would even help....


A general solution is to use a regular expression like this

import re
pattern = re.compile("cheese")

data = 'I love cheese; cheese is my favourite besides cheese.'

count = -1

def f(mo):
  global count
  all_cheeses = ["shredded gorgonzola","bree","camenbert"]
  count += 1
  return all_cheeses[count]

print pattern.sub(f, data)

The call pattern.sub(f, data) substitutes every instance of pattern in the string data by the result of a call to the function f, which must take a "match object" as it's first argument. Here I use a global variable count to keep track of the number of times f was called and select the cheese appropriately ;)

A global variable is usually annoying, so another solution if you want to keep a state information between different substitutions of the same pattern is to create an object class to hold the information like this

class Foo(object):
  cheeses = ["shredded gorgonzola", "bree", "camenbert"]

  def __init__(self):
    self.count = -1

  def __call__(self, mo):
    self.count += 1
    return self.cheeses[self.count % len(self.cheeses)]

print pattern.sub(Foo(), data)

The occurrences of pattern in data are substituted by calling the method __call__ of a Foo object (still with a match object argument). This object holds the count information. Potentially, this technique allows you to replace "cheese" with any substring computed when the replacement is required. You could replace cheese by the current time for example.

For references, see the re module http://docs.python.org/lib/module-re.html

This seems to work:

t = 'I love cheese; cheese is my favourite besides melted cheese.'
cheeses = ["shredded gorgonzola","bree","camenbert"]
for s in cheeses:
    t = t.replace('cheese', s, 1)

Here's another way using the string method index() and slicing:

def str_sub_multiple(s, target, sub_list):
    for sub in sub_list:
            n = s.index(target)
            s = s[:n]+sub+s[n+len(target):]
        except ValueError:
            return s
    return s

print str_sub_multiple(t, 'cheese', ["shredded gorgonzola","bree","camenbert"])