如何在Python中将字符串列表评估为元组列表?

6

我有一个包含成千上万个表单元素的列表,类似于以下内容:

pixels = ['(112, 37, 137, 255)', '(129, 39, 145, 255)', '(125, 036, 138, 255)' ...]

我正在尝试使用ast.literal_eval将这些字符串元素转换为元组,但是遇到像前导零(例如在第三个元组字符串中)之类的东西时会出错,错误信息为SyntaxError: invalid token

pixels = [ast.literal_eval(pixel) for pixel in pixels]

什么是处理此类事物并将字符串列表作为元组列表评估的好方法?

@BhargavRao 在Python 3中,八进制数字不支持0xx格式。 - Ashwini Chaudhary
@BhargavRao 你好。具体错误是SyntaxError: invalid token。我刚刚把它添加到了问题中。 - d3pd
2
@BhargavRao 在 Python 2.x 中,前导的 0 是八进制字面量。但在 Python 3.x 中不再被允许。例如,055 表示十进制值 45 的八进制数。 - Cory Kramer
1
我在等待楼主澄清他是使用2.x还是3.x(因为在2.x中它会变成八进制)。谢谢。 - Bhargav Rao
4
顺便提一下,您可能需要追查产生这个结果的源头,以弄清为什么它输出了“37”和“39”,但是输出的是“036”,以及这种差异是否有任何意义。 - Steve Jessop
@SteveJessop 呵呵,这是由机器学习算法生成的。它做出了很好的努力。 :) - d3pd
2个回答

4
使用 re 模块。
>>> import re
>>> import ast
>>> pixels = ['(112, 37, 137, 255)', '(129, 39, 145, 255)', '(125, 036, 138, 255)']
>>> [ast.literal_eval(re.sub(r'\b0+', '', pixel)) for pixel in pixels]
[(112, 37, 137, 255), (129, 39, 145, 255), (125, 36, 138, 255)]

re.sub(r'\b0+', '', pixel) 的作用是去除前导零。 \b 用于匹配单词字符和非单词字符之间,或者其反向情况,因此这里必须存在一个单词边界,即在零之前和空格或 ( 符号之后。

更新:

>>> pixels = ['(0, 0, 0, 255)', '(129, 39, 145, 255)', '(125, 036, 138, 255)']
>>> [ast.literal_eval(re.sub(r'\b0+\B', '', pixel)) for pixel in pixels]
[(0, 0, 0, 255), (129, 39, 145, 255), (125, 36, 138, 255)]

非常感谢您对此的帮助。您的解决方案非常接近,但它会破坏元组中的零元素,例如,(0, 0, 0, 255)被评估为(, , , 255)。您是否知道解决这个问题的方法? - d3pd
很好的发现,请尝试使用[ast.literal_eval(re.sub(r'\b0+\B', '', pixel)) for pixel in pixels] - Avinash Raj
一种替代的正则表达式方法:[tuple(int(d) for d in re.findall('\d+', pixel)) for pixel in pixels]。(不如已发布的答案好。) - Steven Rumbalski
@AvinashRaj 嘿,非常感谢你在那方面的帮助和清晰的解释。 :) - d3pd

4
不需要使用 ast.literal_evalre。只需去掉括号并将其强制转换为整数即可:
def tupleize(s):
    s = s.strip('()').split(',')
    return tuple(int(entry) for entry in s)

pixels = [tupleize(pixel) for pixel in pixels]

非常感谢您的解决方案。这也是一个很好的方法。 - d3pd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接