I'm looking for a more pythonic way to replace a known length of placeholders in a string with the values found in a list. They should replace in order and only be used once. For example with the values:
replaceVals = ['foo', 'bar']
origStr = 'I went to the ? to get ?'
I am looking to get:
newStr = 'I went to the foo to get bar'
I was able to get the desired result with the following loop, but I feel like there should be a better way to go about this than using a loop like so.
for i in range(len(replaceVals)):
origStr = origStr.replace('?', replaceVals[i], 1)
5 Answers 5
You can use the replace and format methods of the string as shown below:
origStr.replace('?','{}').format(*replaceVals)
Out[334]: 'I went to the foo to get bar'
Comments
Here's an idea using generators:
replaceVals = iter(['foo', 'bar'])
origStr = 'I went to the ? to get ?'
(' ').join(next(replaceVals) if i == '?' else i for i in origStr.split())
Output:
'I went to the foo to get bar'
The advantage of doing it this way, is that the amount of items in replaceVals does not have to match the amount of items to be replaced in origStr:
replaceVals = iter(['foo', 'bar', 'other'])
origStr = 'I went to the ? to get ?'
(' ').join(next(replaceVals) if i == '?' else i for i in origStr.split())
#'I went to the foo to get bar'
However using string formatting would cause errors under these circumstances.
Comments
@roganjosh 's answer in comments is possibly the best, though the OP is abstract enough that it's not clear what his real case is. I was curious whether one could do this with f-strings which showed up in Python3. What makes an f-string less appealing than @roganjosh's, is that it's just so easy to unpack the replacement sequence through the .format() call. That said, IF you wanted to try an f-string, something like this would work:
replaceVals = ['foo', 'bar']
stream = iter(replaceVals)
f'I went to the {stream.next()} to get {stream.next()}'
Comments
f string
r=["foo","bar"]
origStr = f'I went to the {r[0]} to get {r[1]}'
origStr
Out[21]: 'I went to the foo to get bar'
Comments
You can split the string with '?', then use itertools.zip_longest to pair substrings in the resulting list with replacement strings in replaceVals with an empty string as a fill value, and join the pairs of strings after flattening them with a generator expression:
from itertools import zip_longest
''.join(i for p in zip_longest(origStr.split('?'), replaceVals, fillvalue='') for i in p)
origStr = 'I went to the {} to get {}'.format(*replaceVals)