将带有嵌入括号的字符串转换为字典

Posted

技术标签:

【中文标题】将带有嵌入括号的字符串转换为字典【英文标题】:Turning string with embedded brackets into a dictionary 【发布时间】:2015-08-10 11:41:00 【问题描述】:

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

"key1 value1 key2 value2 key3 value with spaces"

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

你会怎么写成:

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

【问题讨论】:

你如何定义“最好的方式”?快速、优雅、可维护……?另外,你自己试过什么?什么有效,什么无效?为什么不呢? 【参考方案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。

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

【讨论】:

以上是关于将带有嵌入括号的字符串转换为字典的主要内容,如果未能解决你的问题,请参考以下文章

在pyspark中将带有字符串json字符串的列转换为带有字典的列

如何将afnetworking json字典转换为字符串,然后在IOS中将字符串转换为字典?

python中如何将字符串转换为字典

如何将字符串字典转换为字典并拆分为单独的列

在使用 Libreoffice 将任何文件转换为 pdf 时,它将日语(unicode)字符转换为括号

将字典转换为字符串,然后再次返回字典