【问题标题】:Convert Python String to Dictionary将 Python 字符串转换为字典
【发布时间】:2013-08-09 22:46:34
【问题描述】:

我有一个字符串:

A = "{user_id:34dd833,category:secondary,items:camera,type:sg_ser}"

我需要把它转换成python字典,这样:

A = {"user_id":"34dd833", "category": "secondary", "items": "camera", "type": "sg_ser"}

除此之外,还有两个问题:

1:“items”键应该有多个值,例如:

A = {"user_id":34dd833, "category": "secondary", "items": "camera,vcr,dvd", "type": "sg_ser"}

这显然是以字符串的形式出现的:

A = "{user_id:34dd833,category:secondary,items:camera,vcr,dvd,type:sg_ser}"

因此,基于逗号分隔来概括任何东西都变得毫无用处。

2:字符串的顺序也可以是随机的。所以,字符串也可以是这样的:

A = "{category:secondary,type:sg_ser,user_id:34dd833,items:camera,vcr,dvd}"

这使得任何按顺序假设变薄的过程都是错误的。

遇到这种情况该怎么办?非常感谢。

【问题讨论】:

  • 34dd833 在您的预期输出中是什么值?你的意思是把它放在引号里吗?还是以 0x 为前缀?还是有什么不同?
  • 哦..对不起..它应该是一个字符串..让我更新问题。
  • 为什么你的输入看起来像这样?它从何而来?我很确定这不是有效的 JSON。
  • 它来自我需要解析的外部来源。不幸的是,我没有任何控制或访问权限来修改它的生成过程。
  • 这是一种可怕的格式。

标签: python json dictionary


【解决方案1】:

如果我们可以假设您的输入没有进行任何引用或转义(您的 示例 没有,但这并不一定意味着这是一个好的假设),并且您永远不能有多个以逗号分隔的键,只有多个值(这可能 一个很好的假设,因为否则格式不明确......):

首先,让我们去掉大括号,然后用冒号分割:

>>> A = "{user_id:34dd833,category:secondary,items:camera,vcr,dvd,type:sg_ser}"
>>> A[1:-1].split(':')
['user_id', '34dd833,category', 'secondary,items', 'camera,vcr,dvd,type', 'sg_ser']

所以第一个条目是第一个键,最后一个条目是最后一个值,中间的每个条目是第 N 个值,后跟一个逗号,然后是第 N+1 个键。那里可能还有其他逗号,但最后一个逗号总是从第 N+1 个键中拆分第 N 个值。 (这甚至适用于 N=0 ——没有逗号,所以最后一个逗号不会从第 0 个键中分割任何内容。但不幸的是,它不适用于最后一个条目。我稍后再谈。)

我们可以通过多种方式来简化此过程,但让我们先将其明确写为代码,以便您了解它的工作原理。

>>> d = {}
>>> entries = A[1:-1].split(':')
>>> for i in range(len(entries)-1):
...     key = entries[i].rpartition(',')[-1]
...     value = entries[i+1].rpartition(',')[0]
...     d[key] = value

这几乎是对的:

>>> d
{'category': 'secondary', 'items': 'camera,vcr,dvd', 'type': '', 'user_id': '34dd833'}

如上所述,它不适用于最后一个。原因应该很明显;如果没有,请查看 rpartition(',') 为最后一个值返回的内容。您可以手动修补它,或者只是通过在末尾添加一个额外的, (entries = (A[1:-1] + ',').split(':')) 来作弊。但是如果你仔细想想,如果你只是rsplit 而不是rpartition,那么[0] 做的事情是正确的。所以让我们这样做吧。

那么,我们怎样才能稍微清理一下呢?

首先让我们将entries 转换为相邻对的列表。现在,每个对的每个(n, nplus1)n.rpartition(',')[-1] 是键,nplus1.rsplit(',', 1)[0] 是对应的值。所以:

>>> A = "{user_id:34dd833,category:secondary,items:camera,vcr,dvd,type:sg_ser}"
>>> entries = A[1:-1].split(':')
>>> adjpairs = zip(entries, entries[1:])
>>> d = {k.rpartition(',')[-1]: v.rsplit(',', 1)[0] for k, v in adjpairs}

【讨论】:

  • 最后一行应该是v.rsplit(',', 1)[0],否则你只会在item中得到“camera”。
  • @PauloAlmeida:谢谢!请注意,我在上面的描述中是正确的。而且我也在我当地的 ipython 中得到了它。这就是为什么你应该总是复制粘贴,然后清理,而不是在复制时清理。 :)
  • @abarnert 我设法杀死了一个正则表达式的怪物,但我喜欢这个 ;)
  • @JonClements:IIRC,几个月前有一个类似的问题,有人粘贴了一个充满回溯的正则表达式解决方案(如果给出错误数据,它会成倍地变慢),并且还会生成 JSON 到parse 而不是直接解析数据。所以,相对于它本来可以很容易做到的东西,你的并不是一个怪物……
  • @abarnert 我很确定pyparsing可以完成一些优雅且易于理解的事情
【解决方案2】:

这是另一种方式(不是特别稳健,但在示例数据上表明它是可能的):

import re
text = "{user_id:34dd833,category:secondary,items:camera,vcr,dvd,type:sg_ser}"
print dict(re.findall(r'(\w+):(.*?)(?=(?:,\w+:)|$)', text.strip('{}')))
# {'category': 'secondary', 'items': 'camera,vcr,dvd', 'user_id': '34dd833', 'type': 'sg_ser'}

【讨论】:

    猜你喜欢
    • 2018-05-19
    • 2013-03-13
    • 2017-03-23
    • 1970-01-01
    • 2020-11-17
    • 1970-01-01
    • 2013-02-03
    • 2011-06-10
    • 2011-03-16
    相关资源
    最近更新 更多