3

The user needs to input a set of coordinates like so (0,0), (0,1), (1,1), (1,0)

The code I wrote for that looks like this:

def get_coords():
    #user_input = raw_input("Enter a list of points. For example (0,0) (0,1) (1,1) (1,0)\n")
    print "Enter a list of points. For example (0,0) (0,1) (1,1) (1,0)\n"
    uin = sys.stdin.readline().strip() 
    try:
    #coords = map(int, uin.split(' '))
    coords = [tuple(map(int, point.replace('(', '').replace(')', '').split(','))) for point in uin.split(' ')]
    return coords
    except ValueError:
    print "Please enter the coordinates in the format mentioned"
    exit()

I'm sure there is a better, more elegant way to do this?

Nathaniel Waisbrot
  • 23,261
  • 7
  • 71
  • 99
meenakshi
  • 90
  • 1
  • 3
  • 10

3 Answers3

2

Replace the spaces with ',' and then apply ast.literal_eval

>>> strs = '(0,0) (0,1) (1,1) (1,0)'
>>> from ast import literal_eval
>>> literal_eval(strs.replace(' ',','))
((0, 0), (0, 1), (1, 1), (1, 0))

Using regex, this would work on any amount of spaces:

>>> import re
>>> strs = '(0, 0)  (0, 1) ( 1, 1)    ( 1,  0)'
>>> literal_eval(re.sub('(\))(\s+)(\()','\g<1>,\g<3>',strs))
((0, 0), (0, 1), (1, 1), (1, 0))
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • Works perfectly, thank you! Although, if I add the commas in the input itself, like "(0,0), (0,1), (1,1), (1,0)" and remove the replace() part from the code, it doesn't work. Why is that? – meenakshi Jun 11 '13 at 17:51
  • @meenakshi It should work fine: `literal_eval("(0,0), (0,1), (1,1), (1,0)")` – Ashwini Chaudhary Jun 11 '13 at 17:52
  • The first example doesn't work for `'(0,0), (0,1), (1,1), (1,0)'.replace(' ',',')`. You get `'(0,0),,(0,1),,(1,1),,(1,0)'`, as you would expect. It would be better to use `split()` and then check if each substring ends with ')'; if not, use `string.rstrip()` with the `chars` argument as `', '`. Or something like that. The difference in your answer and your comment is the lack of `.replace()` in your comment - of course, without it, it works fine! – 2rs2ts Jun 11 '13 at 18:00
  • @2rs2ts There are no commas in the example I've shown in my answer. – Ashwini Chaudhary Jun 11 '13 at 18:03
  • That's what I'm saying. If you don't input commas, you need to do `.replace(' ',',')`, but if you do, you need to NOT do it. – 2rs2ts Jun 11 '13 at 18:15
2
>>> from ast import literal_eval
>>> uin = raw_input("coords: ").split()
coords: (0,0) (0,1) (1,1) (1,0)
>>> uin
['(0,0)', '(0,1)', '(1,1)', '(1,0)']
>>> coords = [literal_eval(coord) for coord in uin]
>>> coords
[(0, 0), (0, 1), (1, 1), (1, 0)]

In your file, you can just write this. Replace the prompt with whatever you like.

from ast import literal_eval
try:
    coords = [literal_eval(coord) for coord in raw_input("coords: ").split()]
except ValueError:
    print "Please enter the coordinates in the format mentioned"
    exit()

literal_eval() raises an exception if the code isn't safe. See the docs.

Regular eval() is bad because it can execute arbitrary code which your user inputs!

Community
  • 1
  • 1
2rs2ts
  • 10,662
  • 10
  • 51
  • 95
1

Just add in commas between the tuples and you can safely evaluate the string into a tuple of tuples:

import ast

def get_coords():
    print "Enter a list of points. For example (0,0), (0,1), (1,1), (1,0)"
    points = raw_input()

    while True:
        try:
            return ast.literal_eval(points)
        except SyntaxError:
            print "Please enter the coordinates in the format mentioned"

You'll get a result similar to:

((0, 0), (0, 1), (1, 1), (1, 0))

And if you absolutely need a list, just pass it through list():

            return list(ast.literal_eval(points))
Blender
  • 289,723
  • 53
  • 439
  • 496