2017-02-09 70 views
4

我有畸形字符串:转换字符串元组与dict

a = '(a,1.0),(b,6.0),(c,10.0)' 

我需要dict

d = {'a':1.0, 'b':6.0, 'c':10.0} 

我尝试:

print (ast.literal_eval(a)) 
#ValueError: malformed node or string: <_ast.Name object at 0x000000000F67E828> 

然后我尝试替换字符来'string dict',它很丑并且不起作用:

b = a.replace(',(','|{').replace(',',' : ') 
    .replace('|',', ').replace('(','{').replace(')','}') 
print (b) 
{a : 1.0}, {b : 6.0}, {c : 10.0} 

print (ast.literal_eval(b)) 
#ValueError: malformed node or string: <_ast.Name object at 0x000000000C2EA588> 

你是做什么的?有什么遗漏?有可能使用regex

+0

那么字符串是商场形式的,因为每个元组的第一个元素不是一个字符,而是一个“a”(这是一个标识符)。 –

+0

是的,我认为这是主要问题。 – jezrael

+0

给定的字符串是否总是具有上述格式?人们确实可以使用正则表达式修复字符串,但是如果输入格式未指定,则正则表达式替换有点危险。 –

回答

3

鉴于该字符串有上述格式,你可以使用正则表达式替换用backrefs

import re 

a = '(a,1.0),(b,6.0),(c,10.0)' 
a_fix = re.sub(r'\((\w+),', r"('\1',",a) 

所以你看一个模式(x,(与x\w秒的顺序和你替代它变成了('x',。其结果则是:

# result 
a_fix == "('a',1.0),('b',6.0),('c',10.0)" 

,然后解析a_fix并将其转换为一个dict:,

>>> dict(ast.literal_eval(a_fix)) 
{'b': 6.0, 'c': 10.0, 'a': 1.0} 
3

如果总是存在括号内的2逗号分隔的值,第二个是一个浮子式的,可以使用

import re 
s = '(a,1.0),(b,6.0),(c,10.0)' 
print(dict(map(lambda (w, m): (w, float(m)), [(x, y) for x, y in re.findall(r'\(([^),]+),([^)]*)\)', s) ]))) 

Python demo和(相当通用)regex demo。这种模式只匹配(,然后0+字符而不是逗号和)捕获到组1中,然后匹配逗号,然后除)(捕获到组2)和)以外的任何0+字符。

正如上面的图案是合适的,当你已经预先验证的数据,正则表达式可以为你当前的数据被限制为

r'\((\w+),(\d*\.?\d+)\)' 

regex demo

详细

  • \( - 一个文字(
  • (\w+) - 捕获组1:一个或更多个字(字母/数字/ _)字符
  • , - 逗号
  • (\d*\.?\d+) - 共同的整数/浮动正则表达式:零个或多个数字,任选.(十进制分离器)和1+数字
  • \) - 字面右括号。
+0

你可以(事实上,我认为你应该)避免使用正则表达式 – BlackBear

+0

@BlackBear:如果验证是必要的,那么正则表达式将是一个优势,我现在添加细节。 –

4

无需正则表达式,如果你的字符串:

result = dict(ast.literal_eval(a_fix)) 

结果在随后是这种格式。

>>> a = '(a,1.0),(b,6.0),(c,10.0)' 
>>> d = dict([x.split(',') for x in a[1:-1].split('),(')]) 
>>> print(d) 
{'c': '10.0', 'a': '1.0', 'b': '6.0'} 

我们除去第一开口括号和最后收盘括号来获得),(通过分裂键 - 值对。这些对然后可以在逗号分割。

要转换为浮动,列表理解变得更长一点:

d = dict([(a, float(b)) for (a, b) in [x.split(',') for x in a[1:-1].split('),(')]]) 
+0

当然,在我的答案中加入了它。嵌套列表解析ftw! –

+1

谢谢你的回答。不幸的是我不能在熊猫中实现,所以我接受另一个答案。 – jezrael

1

为什么eval()剂量不工作的原因是没有定义的a, b, c,我们可以定义那些与它的字符串形式和eval将得到该字符串形式使用

In [11]: text = '(a,1.0),(b,6.0),(c,10.0)' 

In [12]: a, b, c = 'a', 'b', 'c' 

In [13]: eval(text) 
Out[13]: (('a', 1.0), ('b', 6.0), ('c', 10.0)) 

In [14]: dict(eval(text)) 
Out[14]: {'a': 1.0, 'b': 6.0, 'c': 10.0} 

为此在正则表达式的方法:

In [21]: re.sub(r'\((.+?),', r'("\1",', text) 
Out[21]: '("a",1.0),("b",6.0),("c",10.0)' 
In [22]: eval(_) 
Out[22]: (('a', 1.0), ('b', 6.0), ('c', 10.0)) 

In [23]: dict(_) 
Out[23]: {'a': 1.0, 'b': 6.0, 'c': 10.0} 
+2

首先,**'eval' **被认为**非常危险**(因为黑客可能会引入任意代码,请注意OP使用'literal_eval',这是别的东西)。接下来一般情况下,OP不知道密钥是什么,最后,在这里给变量分配了很多值(你可能想用其他值)。 –