user270911
user270911

Reputation: 101

replace iteration in Python

I'd like to replace occurrences of string with different values (from dictionary).

string = 'asfd @@@ fdsfd @@@ ffds @@@ asdf'
kv = {1: 'hi', 2: 'there', 3: 'bla'}

Expected:

string = 'asfd hi fdsfd there ffds bla asdf'

I've tried several solutions particularly with .replace or re.sub but still didn't find a good one.

Upvotes: 1

Views: 2306

Answers (5)

JE_Muc
JE_Muc

Reputation: 5774

A one-line solution:

string.replace('@@@', '{}', len(kv)).format(*kv.values())

Short explanation:

  • Replace all '@@@' strings with the python string formatting identifier '{}'. len(kv) reduces the number of replaces to the length of the dict, avoiding IndexError when the dict has less elements than the number of '@@@' in the string
  • extract dictionary values with kv.values()
  • unpack dictionary values with *kv.values() and pass this as argument to the string format method.

Sample code execution:
Input

string = 'asfd @@@ fdsfd @@@ ffds @@@ asdf'
kv = {'1': 'hi', '2': 'there', '3': 'bla'}

And output

string.replace('@@@', '{}', len(kv)).format(*kv.values())
#Out: 'asfd hi fdsfd there ffds bla asdf'

Advantage of this solution: No explicit looping (explicit looping is almost always a bad idea in python) and only one line of code. Furthermore this is also working when the number of '@@@' is less **or greater than the number of values in kv**, when the count parameter in str.replace is specified.


This leads to the final and 99% failsafe variant of my solution, using the len of the dict as count argument in replace:

string.replace('@@@', '{}', len(kv)).format(*kv.values())

Upvotes: 8

Albin Paul
Albin Paul

Reputation: 3419

You can use re.sub to get the job done with out any sorting

Return the string obtained by replacing the leftmost non-overlapping occurrences of pattern in string by the replacement repl. If the pattern isn’t found, string is returned unchanged. repl can be a string or a function; if it is a string, any backslash escapes in it are processed.

import re
string = 'asfd @@@ fdsfd @@@ ffds @@@ asdf'
kv = {'1': 'hi', '2': 'there', '3': 'bla'}
class repl:
    def __init__(self):
        self.called=0
    def __call__(self,match):
        self.called+=1
        return kv[str(self.called)]
print(re.sub('@@@',repl(),string))

OUTPUT

asfd hi fdsfd there ffds bla asdf

Upvotes: 3

cph_sto
cph_sto

Reputation: 7585

kv = {'1': 'hi', '2': 'there', '3': 'bla'}
string = 'asfd @@@ fdsfd @@@ ffds @@@ asdf'
string_list=string.split('@@@')
string_list_out=[]
for i in range(len(string_list)):
    if i==0:
        string_list_out.append(string_list[0])
    else:
        string_list_out.append(kv[str(i)])
        string_list_out.append(string_list[i])

string_list_out=''.join(string_list_out)
print(string_list_out)
   'asfd hi fdsfd there ffds bla asdf'

Upvotes: 0

DirtyBit
DirtyBit

Reputation: 16772

string = 'asfd @@@ fdsfd @@@ ffds @@@ asdf'
kv = {1: 'hi', 2: 'there', 3: 'bla'}

for k,v in kv.items():
    string = string.replace('@@@', v, 1)
print(string)

OUTPUT:

asfd hi fdsfd there ffds bla asdf

Upvotes: 0

Rakesh
Rakesh

Reputation: 82765

This is one approach using str.replace with optional parameter count.

Ex:

s = 'asfd @@@ fdsfd @@@ ffds @@@ asdf'
kv = {'1': 'hi', '2': 'there', '3': 'bla'}

for k, v in sorted(kv.items()):
    s = s.replace("@@@", v, 1)
print(s)

MoreInfo

Upvotes: 3

Related Questions