Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to parse an arbitrary option string into a python dictionary

I am trying to find the most Pythonic way to take a string containing command line options:

"-t 500 -x -c 3 -d"

And turn it into a dictionary

{"-t":"500", "-x":True, "-c":"3", "-d": True}

UPDATE: The string should also be able to contain --long options, and words with dashes in the middle:

"-t 500 -x -c 3 -d --long-option 456 -testing weird-behaviour"

Before suggesting that I look into OptionParse module, keep in mind I don't know what the valid options are or anything like that, I am just trying to put the string into a dictionary to allow modifying it based on a different dictionary of options.

The approach I am considering is using split() to get the items into a list and then walking the list and looking for items that begin with a dash "-" and use them as the key, and then somehow getting to the next item on the list for the value. The problem I have is with options that don't have values. I thought of doing something like:

for i in range(0, len(opt_list)):
        if opt_list[i][0] == "-":
            if len(opt_list) > i+1 and not opt_list[i+1][0] == "-":
                opt_dict[opt_list[i]] = opt_list[i+1] 
            else:
                opt_dict[opt_list[i]] = True

But it seems like I am programming in C not Python when I do that...

like image 828
Plazgoth Avatar asked Aug 17 '12 17:08

Plazgoth


People also ask

How do I convert a string to a dictionary in Python?

eval() is an inbuilt python library function used to convert string to dictionary efficiently. For this approach, you have to import the ast package from the python library and then use it with the literal_eval() method.

How do I change a string to a dictionary?

Method 1: Splitting a string to generate key:value pair of the dictionary In this approach, the given string will be analysed and with the use of split() method, the string will be split in such a way that it generates the key:value pair for the creation of a dictionary.

How do you parse a variable in Python?

You can use Python's regular expression to parse any string. for your requirement bellow code will give you list of variables( valiables ) and corresponding value( values ) in a list. ([\w]+)= : finds one or more alpha-numeric and underscore( _ ) characters followed by = .

How do I add an item to a dictionary in Python?

There is no add() , append() , or insert() method you can use to add an item to a dictionary in Python. Instead, you add an item to a dictionary by inserting a new index key into the dictionary, then assigning it a particular value.


2 Answers

To handle spaces inside quotes correctly you could use shlex.split():

import shlex

cmdln_args = ('-t 500 -x -c 3 -d --long-option 456 '
              '-testing "weird -behaviour" -m "--inside"')

args = shlex.split(cmdln_args)
options = {k: True if v.startswith('-') else v
           for k,v in zip(args, args[1:]+["--"]) if k.startswith('-')}

from pprint import pprint
pprint(options)

Output

{'--inside': True,
 '--long-option': '456',
 '-c': '3',
 '-d': True,
 '-m': True,
 '-t': '500',
 '-testing': 'weird -behaviour',
 '-x': True}
like image 132
jfs Avatar answered Oct 22 '22 23:10

jfs


You could use regular expressions like so:

import re

args = "-t 500 -x -c 3 -d --long-option 456 -testing weird-behaviour"
matches = re.findall(r'(--?[\w-]+)(.*?)(?= -|$)', args)

result = {}
for match in matches:
    result[match[0]] = True if not match[1] else match[1].strip()

print result

and the result is equal to

{
'-d': True, 
'-c': '3', 
'-t': '500', 
'--long-option': '456', 
'-x': True, 
'-testing': 'weird-behaviour'
}

Regular Expression breakdown:

(--?[\w-]+)(.*?)(?= -|$)

  • (--?[\w-]+) matches any character or word (dashes allowed in the word) that starts with a "-" or a "--".
  • (.*?) matches any character 0 or more times in a non-greedy or minimal fashion by using the question mark.
  • (?= -|$) is a positive lookahead. It checks that what we are looking for is followed by a " -" or the end of the string but it does not include it in the match.

Note the use of parenthesis in this regular expression. These are used to create groups so when we call findall it will split them into tuples.

like image 27
Jay Avatar answered Oct 22 '22 22:10

Jay