flexible find and replace ?

O

OdarR

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
 
B

bearophileHUGS

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
 
J

Jason Scheirer

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.....'
 
T

Tim Chase

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
 
J

John Machin

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
 
G

Gerard Flanagan

OdarR said:
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)
 
G

Gerard Flanagan

Gerard said:
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'))
 
J

John Machin

John Machin said:
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] :)
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,821
Latest member
AleidaSchi

Latest Threads

Top