flexible find and replace ?

Discussion in 'Python' started by OdarR, Feb 16, 2009.

  1. OdarR

    OdarR Guest

    Hi guys,

    how would you do a clever find and replace, where the value replacing
    the tag
    is changing on each occurence ?

    ".......TAG............TAG................TAG..........TAG....."

    is replaced by this :

    ".......REPL01............REPL02................REPL03..........REPL04..."


    A better and clever method than this snippet should exist I hope :

    counter = 1
    while 'TAG' in mystring:
    mystring=mystring.replace('TAG', 'REPL'+str(counter), 1)
    counter+=1
    ...

    (the find is always re-starting at the string beginning, this is not
    efficient.

    any ideas ? thanks,

    Olivier
     
    OdarR, Feb 16, 2009
    #1
    1. Advertising

  2. OdarR

    Guest

    OdarR:

    > how would you do a clever find and replace, where the value replacing
    > the tag is changing on each occurence ?
    > ".......TAG............TAG................TAG..........TAG....."
    > is replaced by this :
    > ".......REPL01............REPL02................REPL03..........REPL04..."



    You may use something like this (tested) replacing XXXXXXXXXXXX with
    the correct re function:

    import re

    def replacer(mobj):
    replacer.counter += 1
    return "REPL%02d" % replacer.counter
    replacer.counter = 0

    print re.XXXXXXXXXXXX("TAG", replacer, s1)

    (If you have more than 99 replacements it will use more than two
    digits.)

    Bye,
    bearophile
     
    , Feb 16, 2009
    #2
    1. Advertising

  3. On Feb 16, 12:10 pm, OdarR <> wrote:
    > Hi guys,
    >
    > how would you do a clever find and replace, where the value replacing
    > the tag
    > is changing on each occurence ?
    >
    > ".......TAG............TAG................TAG..........TAG....."
    >
    > is replaced by this :
    >
    > ".......REPL01............REPL02................REPL03..........REPL04..."
    >
    > A better and clever method than this snippet should exist I hope :
    >
    > counter = 1
    > while 'TAG' in mystring:
    >     mystring=mystring.replace('TAG', 'REPL'+str(counter), 1)
    >     counter+=1
    >     ...
    >
    > (the find is always re-starting at the string beginning, this is not
    > efficient.
    >
    > any ideas ? thanks,
    >
    > Olivier


    You could split on the string and interleave your new string in
    between:

    In [1]: def replmaker():
    ...: index = 0
    ...: while True:
    ...: index += 1
    ...: yield "REPL%02i"%index
    ...:

    In [2]: def spliton(string, tag="TAG", sepgen=replmaker):
    ...: repl_iter = sepgen()
    ...: strlist = string.split(tag)
    ...: length = len(strlist)
    ...: for index, item in enumerate(strlist):
    ...: yield item
    ...: if index < length - 1:
    ...: yield repl_iter.next()
    ...:

    In [3]: ''.join(spliton
    (".......TAG............TAG................TAG..........TAG....." ))
    Out[3]:
    '.......REPL01............REPL02................REPL03..........REPL04.....'
     
    Jason Scheirer, Feb 16, 2009
    #3
  4. OdarR

    Tim Chase Guest

    > how would you do a clever find and replace, where the value replacing
    > the tag
    > is changing on each occurence ?
    >
    > ".......TAG............TAG................TAG..........TAG....."
    >
    > is replaced by this :
    >
    > ".......REPL01............REPL02................REPL03..........REPL04..."




    This is a variant of the class I've used in the past for stateful
    replacements:

    import re

    class Counter(object):
    def __init__(self, prefix="REPL", start=1):
    self.prefix = prefix
    self.counter = start - 1
    def __call__(self, matchobj):
    self.counter += 1
    return "%s%02i" % (self.prefix, self.counter)

    r = re.compile("TAG") # the regexp to find what we want
    s = "some TAG stuff with TAG whatever more TAG stuff"

    print s
    # just use the counter
    print r.sub(Counter(), s)
    # demo a different starting number
    print r.sub(Counter(start=42), s)
    # maintain a single counter across calls
    c = Counter(prefix="Hello", start=42)
    print r.sub(c, s)
    print r.sub(c, s)

    > A better and clever method than this snippet should exist I hope :
    >
    > counter = 1
    > while 'TAG' in mystring:
    > mystring=mystring.replace('TAG', 'REPL'+str(counter), 1)
    > counter+=1
    > ...
    >
    > (the find is always re-starting at the string beginning, this is not
    > efficient.


    This also has problems if your search-string is a substring of
    your replacement string:

    search = "foo"
    replacement = "foobar#"

    You'll get

    s = "foo_foo"
    s = "foobar01_foo"
    s = "foobar02bar01_foo"
    ...

    which isn't quite what it looks like you want.

    -tkc
     
    Tim Chase, Feb 16, 2009
    #4
  5. OdarR

    John Machin Guest

    On Feb 17, 7:10 am, OdarR <> wrote:
    > Hi guys,
    >
    > how would you do a clever find and replace, where the value replacing
    > the tag
    > is changing on each occurence ?
    >
    > ".......TAG............TAG................TAG..........TAG....."
    >
    > is replaced by this :
    >
    > ".......REPL01............REPL02................REPL03..........REPL04..."
    >
    > A better and clever method than this snippet should exist I hope :
    >
    > counter = 1
    > while 'TAG' in mystring:
    >     mystring=mystring.replace('TAG', 'REPL'+str(counter), 1)
    >     counter+=1
    >     ...
    >
    > (the find is always re-starting at the string beginning, this is not
    > efficient.
    >
    > any ideas ? thanks,


    C:\junk>type fancyrepl.py
    def fancyrepl(tag, replfunc, input_string):
    count = 0
    pieces = []
    pos = 0
    taglen = len(tag)
    while 1:
    try:
    newpos = input_string.index(tag, pos)
    except ValueError:
    pieces.append(input_string[pos:])
    return ''.join(pieces)
    pieces.append(input_string[pos:newpos])
    count += 1
    pieces.append(replfunc(count))
    pos = newpos + taglen

    tests = [
    '',
    'XXX',
    'XXXXXX',
    'abcdeXXX',
    'XXXfghij',
    'abcdeXXXfghij',
    'abcdeXXXfghijXXXpqrst',
    ]

    for test in tests:
    print ' <', repr(test)
    result = fancyrepl('XXX', lambda n: 'SUB%d' % n, test)
    print ' >', repr(result)

    C:\junk>fancyrepl.py
    < ''
    > ''

    < 'XXX'
    > 'SUB1'

    < 'XXXXXX'
    > 'SUB1SUB2'

    < 'abcdeXXX'
    > 'abcdeSUB1'

    < 'XXXfghij'
    > 'SUB1fghij'

    < 'abcdeXXXfghij'
    > 'abcdeSUB1fghij'

    < 'abcdeXXXfghijXXXpqrst'
    > 'abcdeSUB1fghijSUB2pqrst'


    HTH,
    John
     
    John Machin, Feb 17, 2009
    #5
  6. OdarR wrote:
    > Hi guys,
    >
    > how would you do a clever find and replace, where the value replacing
    > the tag
    > is changing on each occurence ?
    >
    > ".......TAG............TAG................TAG..........TAG....."
    >
    > is replaced by this :
    >
    > ".......REPL01............REPL02................REPL03..........REPL04..."
    >
    >
    > A better and clever method than this snippet should exist I hope :
    >
    > counter = 1
    > while 'TAG' in mystring:
    > mystring=mystring.replace('TAG', 'REPL'+str(counter), 1)
    > counter+=1
    > ...
    >
    > (the find is always re-starting at the string beginning, this is not
    > efficient.
    >
    > any ideas ? thanks,
    >


    The first thing that comes to mind is re.sub:

    import re

    def replace(s, patt, repls):
    def onmatch(m):
    onmatch.idx += 1
    return repls[onmatch.idx]
    onmatch.idx = -1
    return patt.sub(onmatch, s)

    test = """
    abcTAG TAG asdTAGxyz
    """

    REPLS = [
    'REPL1',
    'REPL2',
    'REPL3',
    ]

    print replace(test, re.compile('TAG'), REPLS)
     
    Gerard Flanagan, Feb 17, 2009
    #6
  7. Gerard Flanagan wrote:
    >
    > def replace(s, patt, repls):
    > def onmatch(m):
    > onmatch.idx += 1
    > return repls[onmatch.idx]
    > onmatch.idx = -1
    > return patt.sub(onmatch, s)
    >


    > test = """
    > abcTAG TAG asdTAGxyz
    > """
    >
    > REPLS = [
    > 'REPL1',
    > 'REPL2',
    > 'REPL3',
    > ]
    >
    > print replace(test, re.compile('TAG'), REPLS)
    >
    > --


    or better:

    import re

    def replace(s, patt, repls):
    repls = iter(repls)
    return patt.sub(lambda m: repls.next(), s)

    test = """
    abcTAG TAG asdTAGxyz
    """

    def repls(tag):
    i = 0
    while True:
    i += 1
    yield tag + str(i)

    print replace(test, re.compile('TAG'), repls('REPL'))
     
    Gerard Flanagan, Feb 17, 2009
    #7
  8. OdarR

    John Machin Guest

    On Feb 17, 7:18 pm, Duncan Booth <> wrote:
    > John Machin <> wrote:
    > > def fancyrepl(tag, replfunc, input_string):
    > >     count = 0
    > >     pieces = []
    > >     pos = 0
    > >     taglen = len(tag)
    > >     while 1:
    > >         try:
    > >             newpos = input_string.index(tag, pos)
    > >         except ValueError:
    > >             pieces.append(input_string[pos:])
    > >             return ''.join(pieces)
    > >         pieces.append(input_string[pos:newpos])
    > >         count += 1
    > >         pieces.append(replfunc(count))
    > >         pos = newpos + taglen

    >
    > Or even:
    >
    > import re, itertools
    > def fancyrepl(tag, replfunc, input_string):
    >         counter = itertools.count(1)
    >         return re.sub(re.escape(tag),
    >          lambda m: replfunc(counter.next()), input_string)
    >
    > which does exactly the same thing


    Not exactly; mine needs
    taglen = max(1, len(tag))
    to stop an infinite loop when len(tag) == 0.

    > in rather less code.


    and with rather less execution speed [measured at about half] and
    rather less OP-explanation speed [guessed] :)
     
    John Machin, Feb 17, 2009
    #8
  9. OdarR

    OdarR Guest

    Thanks to everybody.
    I need to test your propositions now :)

    Olivier
     
    OdarR, Feb 17, 2009
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Eelco Hoogendoorn

    Verbose and flexible args and kwargs syntax

    Eelco Hoogendoorn, Dec 11, 2011, in forum: Python
    Replies:
    1
    Views:
    244
    Steven D'Aprano
    Dec 11, 2011
  2. Eelco Hoogendoorn

    Verbose and flexible args and kwargs syntax

    Eelco Hoogendoorn, Dec 11, 2011, in forum: Python
    Replies:
    0
    Views:
    158
    Eelco Hoogendoorn
    Dec 11, 2011
  3. Eelco Hoogendoorn

    Verbose and flexible args and kwargs syntax

    Eelco Hoogendoorn, Dec 11, 2011, in forum: Python
    Replies:
    0
    Views:
    182
    Eelco Hoogendoorn
    Dec 11, 2011
  4. Eelco Hoogendoorn

    Verbose and flexible args and kwargs syntax

    Eelco Hoogendoorn, Dec 11, 2011, in forum: Python
    Replies:
    88
    Views:
    1,042
    Grant Edwards
    Dec 17, 2011
  5. Eelco Hoogendoorn

    Verbose and flexible args and kwargs syntax

    Eelco Hoogendoorn, Dec 11, 2011, in forum: Python
    Replies:
    0
    Views:
    160
    Eelco Hoogendoorn
    Dec 11, 2011
Loading...

Share This Page