Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I convert a dictionary-like string to a dictionary?

I have a dictionary like string as below:

str = "Access AR1:\n\tTargets: \n\t\tManagement Name:csw_1\n\t\tObject Name:csw_obj_1\n\t\tdetails:103\n\t\tManagement Name:csw_123\n\t\tObject Name:csw_obj_134\n\t\tdetails:123\n\tSources: \n\t\tIP:10.20.30.40\n\t\tSubnet Mask:255.255.255.255\nAccess AR2:\n\tTargets: \n\t\tManagement Name:csw_2\n\t\tObject Name:csw_obj_2\n\t\tdetails:110\n\t\tManagement Name:csw_431\n\t\tObject Name:csw_obj_21\n\t\tdetails:134\n\tSources: \n\t\tIP:10.20.10.10\n\t\tSubnet Mask:255.255.255.192"

and this goes on in the same format, which would look like:

Access AR1:
    Targets: 
            Management Name:csw_1
            Object Name:csw_obj_1
            details:103
            Management Name:csw_123
            Object Name:csw_obj_134
            details:123
    Sources: 
            IP:10.20.30.40
            Subnet Mask:255.255.255.255
Access AR2:
    Targets: 
            Management Name:csw_2
            Object Name:csw_obj_2
            details:110
            Management Name:csw_431
            Object Name:csw_obj_21
            details:134
    Sources: 
            IP:10.20.10.10
            Subnet Mask:255.255.255.192

and this need to be changed to:

str = {"Access AR1": { "Targets": [{"Management Name:csw_1", "Object Name":"csw_obj_1", "details":"103"}, {"Management Name:csw_123", "Object Name":"csw_obj_134", "details":"123"}]
                      "Sources": {"IP":"10.20.30.40", "Subnet Mask": "255.255.255.255"}
                    },
      "Access AR2": { "Targets": [{"Management Name:csw_2", "Object Name":"csw_obj_2", "details":"110"}, {"Management Name:csw_431", "Object Name":"csw_obj_21", "details":"133"}]
                      "Sources": {"IP":"10.20.10.10", "Subnet Mask": "255.255.255.192"}
                    }
      }

I tried ast.literal_eval, eval and ended up with an error.

like image 703
nonuser Avatar asked Jul 05 '21 14:07

nonuser


People also ask

How do you turn a string of a dictionary into a dictionary?

To convert a Python string to a dictionary, use the json. loads() function. The json. loads() is a built-in Python function that converts a valid string to a dict.

Can we convert string to dictionary in Python?

You can easily convert python string to the dictionary by using the inbuilt function of loads of json library of python. Before using this method, you have to import the json library in python using the “import” keyword.

Can a string be a dictionary key?

Second, a dictionary key must be of a type that is immutable. For example, you can use an integer, float, string, or Boolean as a dictionary key.

How to convert a string to a dictionary in Python?

You can use the ast.literal_eval () function to convert the string representation of a dictionary to a dictionary in Python. The following is the syntax. It returns a dictionary. We get the result as a dictionary. Alternatively, you can use the json.loads () function to convert a string representation of a dictionary to a dictionary in Python.

How to write a dictionary in Python with a colon?

The key and its corresponding value are separated by a colon (:). And each key:value pair in the dictionary is separated by a comma (,). A dictionary in Python is always enclosed in the curly brackets {}.

What are the features of Python dictionary?

The most important feature of the python dictionaries is that they don’t allow polymorphism. Also, the keys in the dictionary are case-sensitive. Therefore, the uppercase and lowercase keys are considered different from each other. Later, you can access the dictionary data by referring to its corresponding key name.


Video Answer


3 Answers

Your string is nearly yaml - replace the \t with one or more spaces and it loads as YAML.

First:

pip install pyyaml

Then this code works:

import yaml
import pprint

str = "Access AR1:\n\tTargets: \n\t\tManagement Name:csw_1\n\t\tObject Name:csw_obj_1\n\t\tdetails:103\n\tSources: \n\t\tIP:10.20.30.40\n\t\tSubnet Mask:255.255.255.255\nAccess AR2:\n\tTargets: \n\t\tManagement Name:csw_2\n\t\tObject Name:csw_obj_2\n\t\tdetails:110\n\tSources: \n\t\tIP:10.20.10.10\n\t\tSubnet Mask:255.255.255.192"

str1 = str.replace( '\t', '    ' )

res = yaml.load(str1)

pprint.pprint( res )

Output:

{'Access AR1': {'Sources': 'IP:10.20.30.40 Subnet Mask:255.255.255.255',
                'Targets': 'Management Name:csw_1 Object Name:csw_obj_1 '
                           'details:103'},
 'Access AR2': {'Sources': 'IP:10.20.10.10 Subnet Mask:255.255.255.192',
                'Targets': 'Management Name:csw_2 Object Name:csw_obj_2 '
                           'details:110'}}

Or, if you really want this as a string then:

str = repr(res)

UPDATE

Just realised that e.g. 'Managent Name:csw_1' isn't being detected as a key:value. Needed a regex re.sub() to split these onto separate lines to fix this:

import yaml
import pprint
import re

str = "Access AR1:\n\tTargets: \n\t\tManagement Name:csw_1\n\t\tObject Name:csw_obj_1\n\t\tdetails:103\n\tSources: \n\t\tIP:10.20.30.40\n\t\tSubnet Mask:255.255.255.255\nAccess AR2:\n\tTargets: \n\t\tManagement Name:csw_2\n\t\tObject Name:csw_obj_2\n\t\tdetails:110\n\tSources: \n\t\tIP:10.20.10.10\n\t\tSubnet Mask:255.255.255.192"

# replace \t with four-space indent
str1 = str.replace( '\t', '    ' )

# further tweak to split sub-keys like " Management Name:csw_1" onto separate lines
str1 = re.sub(r"^(\s+)(.*?\S:)(\S.*)", r"\1\2\n\1    \3",str1,flags=re.MULTILINE )
   
res = yaml.load(str1)

pprint.pprint( res )

This is the string after tweaks:

Access AR1:
    Targets:
        Management Name:
            csw_1
        Object Name:
            csw_obj_1
        details:
            103
    Sources:
        IP:
            10.20.30.40
        Subnet Mask:
            255.255.255.255
Access AR2:
    Targets:
        Management Name:
            csw_2
        Object Name:
            csw_obj_2
        details:
            110
    Sources:
        IP:
            10.20.10.10
        Subnet Mask:
            255.255.255.192

Result:

{'Access AR1': {'Sources': {'IP': '10.20.30.40',
                            'Subnet Mask': '255.255.255.255'},
                'Targets': {'Management Name': 'csw_1',
                            'Object Name': 'csw_obj_1',
                            'details': 103}},
 'Access AR2': {'Sources': {'IP': '10.20.10.10',
                            'Subnet Mask': '255.255.255.192'},
                'Targets': {'Management Name': 'csw_2',
                            'Object Name': 'csw_obj_2',
                            'details': 110}}}
like image 75
DisappointedByUnaccountableMod Avatar answered Oct 21 '22 00:10

DisappointedByUnaccountableMod


Hello this is the solution you need

strr = "Access AR1:\n\tTargets: \n\t\tManagement Name:csw_1\n\t\tObject Name:csw_obj_1\n\t\tdetails:103\n\tSources: \n\t\tIP:10.20.30.40\n\t\tSubnet Mask:255.255.255.255\nAccess AR2:\n\tTargets: \n\t\tManagement Name:csw_2\n\t\tObject Name:csw_obj_2\n\t\tdetails:110\n\tSources: \n\t\tIP:10.20.10.10\n\t\tSubnet Mask:255.255.255.192"
nvstr=strr.replace("\n\t\t","-").replace("\n\t","+")
#print(nvstr)
nvdd={}
for u in nvstr.split("\n"):
   #print(u) 
   dts=u.split("+") 
   
   nvdd[dts[0]]={}
   
   for el in dts[1:]:
       
     dts1=el.split("-")
     nvdd[dts[0]][dts1[0][:-1]]={}
     for el1 in dts1[1:]:
         
       k,v=el1.split(":")
       nvdd[dts[0]][dts1[0][:-1]][k]=v
       
print(nvdd)    
like image 2
Bahae El Hmimdi Avatar answered Oct 21 '22 02:10

Bahae El Hmimdi


You can use recursion to convert the input to a dictionary, without having to make any adjustments to the string itself beforehand:

import re
s = "Access AR1:\n\tTargets: \n\t\tManagement Name:csw_1\n\t\tObject Name:csw_obj_1\n\t\tdetails:103\n\tSources: \n\t\tIP:10.20.30.40\n\t\tSubnet Mask:255.255.255.255\nAccess AR2:\n\tTargets: \n\t\tManagement Name:csw_2\n\t\tObject Name:csw_obj_2\n\t\tdetails:110\n\tSources: \n\t\tIP:10.20.10.10\n\t\tSubnet Mask:255.255.255.192"
def to_dict(d):
   k, v, r = None, [], {}
   for *b, a in d:
     if not b:
        if k is not None:
           if not v:
              r[j[0]] = (j:=re.split(':\s*', k))[-1]
           else:
              r[re.split(':\s*', k)[0]] = to_dict(v)
        k, v = a, []
     else:
         v.append([*b[1:], a])
   if k is not None:
       if not v:
          r[j[0]] = (j:=re.split(':\s*', k))[-1]
       else:
          r[re.split(':\s*', k)[0]] = to_dict(v)
   return r

import json       
new_s = [re.findall('\t|[^\t]+$', i) for i in s.split('\n')]
print(json.dumps(to_dict(new_s), indent=4))

Output:

{
    "Access AR1": {
        "Targets": {
            "Management Name": "csw_1",
            "Object Name": "csw_obj_1",
            "details": "103"
        },
        "Sources": {
            "IP": "10.20.30.40",
            "Subnet Mask": "255.255.255.255"
        }
    },
    "Access AR2": {
        "Targets": {
            "Management Name": "csw_2",
            "Object Name": "csw_obj_2",
            "details": "110"
        },
        "Sources": {
            "IP": "10.20.10.10",
            "Subnet Mask": "255.255.255.192"
        }
    }
}
like image 1
Ajax1234 Avatar answered Oct 21 '22 00:10

Ajax1234