18

I have strings which look like this one:

"(8, 12.25), (13, 15), (16.75, 18.5)"

and I would like to convert each of them into a python data structure. Preferably a list (or tuple) of tuples containing a pair of float values.

I could do that with eval("(8, 12.25), (13, 15), (16.75, 18.5)") which gives me a tuple of tuples, but I don't think naively evaluating external information would be a wise decision.

So I wondered what an elegant pythonic solution might look like.

tosh
  • 5,222
  • 2
  • 28
  • 34

6 Answers6

27
>>> import ast
>>> print ast.literal_eval("(8, 12.25), (13, 15), (16.75, 18.5)")
((8, 12.25), (13, 15), (16.75, 18.5))
nosklo
  • 217,122
  • 57
  • 293
  • 297
  • 1
    jfyi, this might not be robust to having a single tuple in the list. What if you input was "(8, 12.25)". That you would get just a tuple instead of a tuple in a tuple. I believe you would get the desired nested tuple if the input was "(8, 12.25)," (note the trailing comma). But I didn't test this as I do not have python 2.6 installed on this machine. – Tom Nov 27 '09 at 19:05
  • Good catch Tom. I did not think about that yet and it would actually be a problem in my situation. I am going to check for that after parsing. Thank's for the heads up. Unfortunately the method is not available in python2.5 but In my case that is ok as I am using it in an app engine data import script and not in app engine itself. – tosh Nov 27 '09 at 19:26
  • +1: Didn't know `ast.literal_eval` before -- and it's so handy! – Florian Brucker Sep 26 '12 at 15:04
4
def parse(s):
    tuples = s.split('), ')
    out = []
    for x in tuples:
        a,b = x.strip('()').split(', ')
        out.append((float(a),float(b)))
    return out

this should do the job.

2

I've used safe_eval for jobs like this in the past.

Community
  • 1
  • 1
Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
1

If you're working with a CSV file, and you want more than the "naive" solution which doesn't handle any errors, you're probably best off using the Python's CSV module.

Edan Maor
  • 9,772
  • 17
  • 62
  • 92
  • Sorry I defined the question a bit vague. The string is actually a value that I get as one of the comma/semicolon separated values. I will remove the CSV bit from the question as it might be confusing. I am using the CSV module by the way. It is great. Thanks for answering though. – tosh Nov 27 '09 at 18:32
1

Download PyParsing.

I've worked with it before. You can get some pretty robust parsing behavior out of it, and I think it provides builtins that will handle your entire parsing needs with this sort of thing. Look up commaSeparatedList and nestedExpr.

inklesspen
  • 1,146
  • 6
  • 11
1

what's wrong with doing it systematically ? split on ")", then go through the list, remove all "(".

>>> s="(8, 12.25), (13, 15), (16.75, 18.5)"
>>> [ i.replace("(","") for i in s.split(")") ]
['8, 12.25', ', 13, 15', ', 16.75, 18.5', '']
>>> b = [ i.replace("(","") for i in s.split(")") ]
>>> for i in b:
...  print i.strip(", ").replace(" ","").split(",")
...
['8', '12.25']
['13', '15']
['16.75', '18.5']
['']

Now you can bring each element into your data structure.

ghostdog74
  • 327,991
  • 56
  • 259
  • 343