Kaushal28
Kaushal28

Reputation: 5565

Format String of Dictionary

I've a string of dictionary as following:

CREDENTIALS = "{\"aaaUser\": {\"attributes\": {\"pwd\": \"cisco123\", \"name\": \"admin\"}}}"

Now I want to format this string to replace the pwd and name dynamically. What I've tried is:

CREDENTIALS = "{\"aaaUser\": {\"attributes\": {\"pwd\": \"{0}\", \"name\": \"{1}\"}}}".format('password', 'username')

But this gives following error:

traceback (most recent call last):
File ".\ll.py", line 4, in <module>
    CREDENTIALS = "{\"aaaUser\": {\"attributes\": {\"pwd\": \"{0}\", \"name\": \"{1}\"}}}".format('password', 'username')
KeyError: '"aaaUser"

It is possible by just loading the string as dict using json.loads()and then setting the attributes as required, but this is not what I want. I want to format the string, so that I can use this string in other files/modules. '

What I'm missing here? Any help would be appreciated.

Upvotes: 0

Views: 126

Answers (2)

MaNKuR
MaNKuR

Reputation: 2704

str.format deals with the text enclosed with braces {}. Here variable CREDENTIALS has the starting letter as braces { which follows the str.format rule to replace it's text and find the immediately closing braces since it don't find it and instead gets another opening braces '{' that's why it throws the error.

The string on which this method is called can contain literal text or replacement fields delimited by braces {}

Now to escape braces and replace only which indented can be done if enclosed twice like

'{{ Hey Escape }} {0}'.format(12)   # O/P '{ Hey Escape } 12'

If you escape the parent and grandparent {} then it will work.

Example:

'{{Escape Me {n} }}'.format(n='Yes')  # {Escape Me Yes}

So following the rule of the str.format, I'm escaping the parents text enclosed with braces by adding one extra brace to escape it.

"{{\"aaaUser\": {{\"attributes\": {{\"pwd\": \"{0}\", \"name\": \"{1}\"}}}}}}".format('password', 'username')

 #O/P '{"aaaUser": {"attributes": {"pwd": "password", "name": "username"}}}'

Now Coming to the string formatting to make it work. There is other way of doing it. However this is not recommended in your case as you need to make sure the problem always has the format as you mentioned and never mess with other otherwise the result could change drastically.

So here the solution that I follow is using string replace to convert the format from {0} to %(0)s so that string formatting works without any issue and never cares about braces .

'Hello %(0)s' % {'0': 'World'}  # Hello World

SO here I'm using re.sub to replace all occurrence

def myReplace(obj):
     found = obj.group(0)
     if found:
         found = found.replace('{', '%(')
         found = found.replace('}', ')s')
         return found
CREDENTIALS = re.sub('\{\d{1}\}', myReplace, "{\"aaaUser\": {\"attributes\": {\"pwd\": \"{0}\", \"name\": \"{1}\"}}}"% {'0': 'password', '1': 'username'}
print CREDENTIALS  # It should print desirable result

Upvotes: 1

chepner
chepner

Reputation: 532208

Don't try to work with the JSON string directly; decode it, update the data structure, and re-encode it:

# Use single quotes instead of escaping all the double quotes
CREDENTIALS = '{"aaaUser": {"attributes": {"pwd": "cisco123", "name": "admin"}}}'

d = json.loads(CREDENTIALS)
attributes = d["aaaUser"]["attributes"]
attributes["name"] = username
attributes["pwd"] = password
CREDENTIALS = json.dumps(d)

With string formatting, you would need to change your string to look like

CREDENTIALS = '{{"aaaUser": {{"attributes": {{"pwd": "{0}", "name": "{1}"}}}}}}'

doubling all the literal braces so that the format method doesn't mistake them for placeholders.

However, formatting also means that the password needs to be pre-escaped if it contains anything that could be mistaken for JSON syntax, such as a double quote.

# This produces invalid JSON
NEW_CREDENTIALS = CREDENTIALS.format('new"password', 'bob')

# This produces valid JSON
NEW_CREDENTIALS = CREDENTIALS.format('new\\"password', 'bob')

It's far easier and safer to just decode and re-encode.

Upvotes: 1

Related Questions