将带有嵌入括号的字符串转换为字典
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 ” @mtmtprint 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<Brace>\)
保存了 的匹配,之后
(?(Brace)\)
将匹配,仅当第一个匹配时,因此大括号必须成对出现。通过
(?(Brace)...|...)
构造,如果\Brace
匹配,则值部分可以包含除大括号([^]*
)之外的任何内容,否则不允许有空格([^\s]*
)。
由于可选大括号在正则表达式中匹配,因此在列表中返回,我们需要通过map()
函数从每个列表中提取元素0和2。
正则表达式很容易变得混乱。
【讨论】:
以上是关于将带有嵌入括号的字符串转换为字典的主要内容,如果未能解决你的问题,请参考以下文章
在pyspark中将带有字符串json字符串的列转换为带有字典的列
如何将afnetworking json字典转换为字符串,然后在IOS中将字符串转换为字典?