【问题标题】:Turning string with embedded brackets into a dictionary将带有嵌入括号的字符串转换为字典
【发布时间】:2023-03-31 10:48:01
【问题描述】:

从下面的字符串构建字典的最佳方法是什么:

"{key1 value1} {key2 value2} {key3 {value with spaces}}"

所以键始终是一个没有空格的字符串,但值是一个字符串或大括号中的字符串(它有空格)?

你会怎么写成:

{'key1': 'value1',   'key2': 'value2',   'key3': 'value with spaces'}

【问题讨论】:

  • 你如何定义“最好的方式”?快速、优雅、可维护……?另外,你自己试过什么?什么有效,什么无效?为什么不呢?

标签: python regex dictionary


【解决方案1】:
import re
x="{key1 value1} {key2 value2} {key3 {value with spaces}}"
print dict(re.findall(r"\{(\S+)\s+\{*(.*?)\}+",x))

你可以试试这个。

输出:

{'key3': 'value with spaces', 'key2': 'value2', 'key1': 'value1'}

这里用re.findall 提取key,它的value.re.findall 返回一个包含所有键值对的元组的列表。在元组列表上使用dict 提供最终答案。 Read more here.

【讨论】:

  • 这真是太棒了!如果您能发布一点解释,那就太好了,这样我就可以更好地学习和理解这一点。谢谢。
  • @vks 太好了!我将如何更新它以支持括号中带有空格的情况,如下所示:“{ key1 value1 } { key2 value2 } { key3 {value with spaces} }”
  • @mtmt print dict(re.findall(r"\{\s*(\S+)\s+\{*(.*?)\}+",x))
  • 实际上对于带有空格的情况,这将是一个简单的更改 "\{ (\S+)\s+\{(.?)\}+" 我只需要想办法支持这两种情况
  • @mtmt 将其更改为 \s* 以支持这两种情况
【解决方案2】:

我不能让它更优雅:

input = "{key1 value1} {key2 value2} {key3 {value with spaces}}"
x = input.split("} {")             # creates list with keys and values
y = [i.split(" {") for i in y]     # separates the list-values from keys
# create final list with separated keys and values, removing brackets
z = [[i.translate(None,"{").translate(None,"}").split() for i in j] for j in y]

fin = {}
for i in z:
    fin[i[0][0]] = i[-1]

这很 hacky,但它应该可以完成这项工作。

【讨论】:

  • 认为第三个值是一个值列表。无论如何,vks 的回答要好得多。
  • 这可能有点骇人听闻,但似乎避免了明显的正则表达式,这在某些情况下可能是有益的。
【解决方案3】:

假设您的字符串中没有比示例中更嵌套的内容,您可以首先使用前瞻/后瞻断言将字符串拆分为键值对,查找模式 } { (一对括号的结尾和另一个括号的开头。)

>>> str = '{key1 value1} {key2 value2} {key3 {value with spaces}}'
>>> pairs = re.split('(?<=})\s*(?={)', str)

这表示“匹配前面有 } 和后面有 { 的任何 \s*(空白),但不要在匹配项本身中包含这些括号。”

然后你就有了你的键值对:

>>> pairs
['{key1 value1}', '{key2 value2}', '{key3 {value with spaces}}']

可以在 maxsplit 参数设置为 1 的情况下在空格上拆分,以确保它仅在第一个空格上拆分。在这个例子中,我还使用了字符串索引([1:-1])来去掉我知道的位于每对开头和结尾的花括号。

>>> simple = pairs[0] 
>>> complex = pairs[2]  
>>> simple
'{key1 value1}'
>>> complex
'{key3 {value with spaces}}'
>>> simple[1:-1]
'key1 value1'
>>> kv = re.split('\s+', simple[1:-1], maxsplit=1)
>>> kv
['key1', 'value1']
>>> kv3 = re.split('\s+', complex[1:-1], maxsplit=1)
>>> kv3
['key3', '{value with spaces}']

然后只需检查值是否包含在花括号中,如果需要,在将它们放入字典之前将其删除。

如果保证键/值对总是由单个空格字符分隔,那么您可以改用普通的旧字符串拆分。

>>> kv3 = complex[1:-1].split(' ', maxsplit=1)
>>> kv3
['key3', '{value with spaces}']

【讨论】:

    【解决方案4】:

    @vks 的答案不检查平衡括号。请尝试以下操作:

    >>> x="{key3 {value with spaces} {key4 value4}}"
    >>> dict(re.findall(r"\{(\S+)\s+\{*(.*?)\}+",x))
    {'key3': 'value with spaces', 'key4': 'value4'}
    

    试试吧:

    >>> dict(map(lambda x:[x[0],x[2]], re.findall(r'\{(\S+)\s+(?P<Brace>\{)?((?(Brace)[^{}]*|[^{}\s]*))(?(Brace)\})\}',x)))
    {'key4': 'value4'}
    

    也就是说,它只匹配正确支撑的部分。

    (?P&lt;Brace&gt;\{) 保存了{ 的匹配,之后(?(Brace)\}) 将匹配},仅当第一个匹配时,因此大括号必须成对出现。通过(?(Brace)...|...) 构造,如果\Brace 匹配,则值部分可以包含除大括号([^{}]*)之外的任何内容,否则不允许有空格([^{}\s]*)。

    由于可选大括号在正则表达式中匹配,因此在列表中返回,我们需要通过map()函数从每个列表中提取元素0和2。

    正则表达式很容易变得混乱。

    【讨论】:

      猜你喜欢
      • 2012-01-28
      • 2022-12-10
      • 2014-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-21
      • 2022-07-20
      相关资源
      最近更新 更多