2

I have a list, that looks like this in python:

ex = ['(1..3),(5..8)']

I need to get out the list like this:

[(1, 3), (5, 8)]

I tried using the replace function, but could only get like ['(1, 3), (5,8)'] and could not lose the ' marks.

Hope someone can help me.

Thanks

2
  • Are you trying to convert that string into a list of tuples or just another string representation? Commented Dec 16, 2011 at 7:14
  • 1
    You're trying to change a string to some tuples. You can't do that with replacing string contents. Try something like eval. Commented Dec 16, 2011 at 7:14

4 Answers 4

8
import ast
ex = ['(1..3),(5..8)']
list(ast.literal_eval(ex[0].replace('..', ',')))
# returns [(1, 3), (5, 8)]

ast.literal_eval is safe. eval is not.

For your updated question:

ex2 = ['(2..5)', '(7..10)']
[ast.literal_eval(a.replace('..', ',')) for a in ex2]
# returns [(2, 5), (7, 10)]
Sign up to request clarification or add additional context in comments.

3 Comments

Thx for the quick answer, this was just what I was looking for. And now comes the twist. What is my input list looks like this now: ex2 = ['(2..5)', '(7..10)']. Then I can not just use the ex[0] like above, but have to get both.
Again you provide me with a beautiful answer :) Just to make sure I understand this properly: do I now have a list with tuples, or just a list containing "(" and ")"? I hope you understand what I mean. Is it possible to get out only the number 2 fx from the list created?
@X-Pender - [(2, 5), (7, 10)] is a list of tuples of integers. You can access its elements: result[0][1] == 2. Just start ipython, paste the lines into it and try yourself.
2

Look like some regex task.

>>> import re
>>> ex = ['(1..3),(5..8)']
>>> re.findall(r'\((\d+)\.\.(\d+)\)', ex[0])
[('1', '3'), ('5', '8')]
>>> # if you want tuple of numbers
... [tuple(map(int, x)) for x in _]
[(1, 3), (5, 8)]

1 Comment

+1: the form of each pair is explicit and quite clear. However, this parsing does not put many constraints on the input string, and might therefore let some bugs pass silently (for example, (1..3) xxx (5..8) 12, 3 is accepted even though it does not have the right format).
2

This became uglier than I expected:

In [26]: ex = ['(1..22),(3..44)']

In [27]: [tuple([int(i) for i in s.strip('()').split('..')])
          for s in ex[0].split(',')]
Out[27]: [(1, 22), (3, 44)]

2 Comments

+1 because this is a general approach that has the virtue of making the form of the input string explicit. Parsing errors are also more explicit, with this method. I find the regex approach to be a tad more explicit, though.
Thanks. I agree, this solution is hackish and confusing, but I guess it answers the question.
1

if your format is constant, this should work :

  >>> n = list(eval(ex[0].replace("..",",")))
  >>> n
  [(1, 3), (5, 8)]

UPDATE : using literal eval ( safer ):

import ast
result = list(ast.literal_eval(ex[0].replace("..",",")))

4 Comments

It's best not to use eval directly if possible, an alternative for literals is literal_eval from ast, also this doesnt work if ex only has one element.
And just for future reference (to OP), always remember that it is UNSAFE to eval a string that a user can manipulate in any way. You can do safe eval using ast.literal_eval(). Edit: @Doboy: Beat me to it!
@JohnDoe Thanks for the improvement .
@gb. yes you can, I should have replaced it with literal_eval.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.