【问题标题】:Translate key-value string with arrays into json object in python将带有数组的键值字符串转换为python中的json对象
【发布时间】:2023-03-08 03:16:01
【问题描述】:

我有一个(平面)文本字符串,我想将其翻译成 python 字典/json。

示例字符串:

key1=value key2="val ue" key3=[entry1, entry2] key4=["o ne", "[two]"] key5="value with a , or secial character#l" key6="text with a protected quotation \" inside" key7=1,101,42

输出应该是一个 dict/json 看起来像

{
"key1": "value",
"key2": "val ue",
"key3": ["entry1", "entry2"],
"key4": ["o ne", "[two]"],
"key5": "value with a , or secial character#l",
"key6":"text with a protected quotation \" inside",
"key7": [1,101,42]
}

我使用的是这里描述的词法分析器https://www.debugcn.com/en/article/15212391.html,但我坚持如何将它与括号一起使用...

    def parse_kv_pairs(text):
        lexer = shlex.shlex(text, posix=True)
        lexer.whitespace = " "
        lexer.wordchars += "="
        lexer.quotes = "\""
        lexer.wordchars += ".-_()/:+*^&%$#@!?|{}[]'`´,"
        return dict(word.split(value_sep, maxsplit=1) for word in lexer)

你知道支持这个的库或者你有能够翻译这个的算法吗?

我为任何成功感到高兴:)

【问题讨论】:

  • 欢迎来到 StackOverflow。展示您迄今为止尝试过的内容(代码),并具体说明哪个部分给您带来了麻烦。
  • 您确定不能获得不同的输入吗?我可以想象一个解析这个的算法,但是写起来会很乏味,而且我认为有很多边缘情况很难覆盖。例如,如何区分 [1,2] 和 "1,2"
  • @aneroid 我添加了代码。要处理的主要问题是表示 [] 括号的数组。
  • @OndřejBaštař 不幸的是不可能。 [1,2] 是一个数字数组。数组必须始终由括号引入,因此“1,2”只是一个包含逗号的字符串,参见 key5(或 key2)
  • 好的。您的示例实际上非常广泛。我觉得必须创建一个自定义算法。尝试这样做,我们可以帮助您调试或希望有人会为您这样做。不过我听起来没那么糟糕。您甚至可以使用 eval() 来帮助您,但只有您可以确定字符串是安全的。

标签: python arrays json algorithm dictionary


【解决方案1】:

我们可以假设这些值(等号之后)是 JSON 兼容的,但有两个例外:

  • 字词可能不带引号
  • 列表可能不带方括号(它们被逗号分隔符识别)

因此,如果我们可以捕获等号之后的部分,我们可以:

  1. 识别带引号的字符串
  2. 用双引号将每个未加引号的单词(以字母开头)括起来
  3. 将其解析为 JSON。
  4. 如果上一步失败,用方括号括起来并再次解析为 JSON

这是建议的代码:

import re 
import json

def parse(s):
    d = {}
    key = value = ""
    for m in re.findall(r'"(?:[^"\\]|\\.)*"|\w+=?|\S', s) + ["="]:
        if m[-1] == '=':  # Arrived at a new key/value pair
            if key:  # Process previous key/value pair
                try:
                    d[key] = json.loads(value)
                except Exception: # Try with brackets, if that fails: input is bad
                    d[key] = json.loads("[{}]".format(value))
            key = m[:-1]  # New key
            value = ""
        elif m[0].isalpha():  # Wrap in quotes
            value += '"{}"'.format(m)
        else:  # Punctuation, digits, ...
            value += m
    return d

对于您提供的示例数据,您将如何调用该函数:

s = r'key1=value key2="val ue" key3=[entry1, entry2] key4=["o ne", "[two]"] key5="value with a , or secial character#l" key6="text with a protected quotation \" inside" key7=1,101,42'

result = parse(s)

结果将是:

{
   'key1': 'value', 
   'key2': 'val ue', 
   'key3': ['entry1', 'entry2'], 
   'key4': ['o ne', '[two]'], 
   'key5': 'value with a , or secial character#l', 
   'key6': 'text with a protected quotation " inside', 
   'key7': [1, 101, 42]
}

【讨论】:

  • 非常感谢@trincot。其实我最喜欢这个主意。我做了一些正则表达式修改以支持电子邮件地址作为值。正则表达式:r'"(?:[^"\]|\\.)*"|[a-zA-Z0-9@$.!_-]+=?|\S
【解决方案2】:

我尝试使用正则表达式来理解您想要什么。我坚持使用示例中的所有小写字母,并添加了几个我自己的额外陷阱键以进行测试。

我假设数字中的任何逗号都可以被剥离并将任何空白字符编码为等同于空格,从而允许在空格处使用额外的换行符而不是长输入来分割输入,(或者不可以 - 它可以被删除)。代码运行,最后的断言显示了它产生的结果。

列表不能嵌套。

# -*- coding: utf-8 -*-
"""
https://stackoverflow.com/questions/66491209/translate-key-value-string-with-arrays-into-json-object-in-python

Created on Fri Mar  5 18:52:01 2021

@author: paddy3118
"""
import re

data = r"""
key1=value key2="val ue" key3=[entry1, entry2] key4=["o ne", "[two]"]
key5="value with a , or secial character#l"
key6="text with a protected quotation \" inside" key7=1,101,42
key8=key9 key10="not a key0=whatewver"
"""
data = data.strip()
space = '\t \n\r'
i = 0
state = 'KEY'
d = {}  # dict for parsed data
while data:
    if state == 'KEY':
        if not (m := re.search(r'^([a-z0-9]+)=', data)):
            break  # d, data
        key = m.groups()[0]
        data = data[m.end():]
        state = 'VAL'
    if state in {'VAL', 'LISTVAL'}:
        if (m:= re.search('^([a-z][a-z0-9]+)[\s,]*', data)):
            val = m.groups()[0]
            if state == 'VAL':
                d[key] = val
                state = 'KEY'
            else:
                listval.append(val)
            data = data[m.end():]
        elif (m:= re.search(r'^"(.*?[^\\])"[\s,]*', data)):
            val = m.groups()[0]
            if state == 'VAL':
                d[key] = val
                state = 'KEY'
            else:
                listval.append(val)
            data = data[m.end():]
        elif (m:= re.search(r'^([0-9][0-9.,]*[^,])[\s,]*', data)):
            val = m.groups()[0]
            val = float(val.replace(',', ''))
            val = int(val) if val.is_integer() else val
            if state == 'VAL':
                d[key] = val
                state = 'KEY'
            else:
                listval.append(val)
            data = data[m.end():]
        elif state == 'VAL' and data[0] == '[':
            listval = []
            state = 'LISTVAL'
            data = data[1:].lstrip()
        elif state == 'LISTVAL' and data[0] == ']':
            d[key] = listval
            state = 'KEY'
            data = data[1:].lstrip()
        else:
            break

assert d == {'key1': 'value',
 'key2': 'val ue',
 'key3': ['entry1', 'entry2'],
 'key4': ['o ne', '[two]'],
 'key5': 'value with a , or secial character#l',
 'key6': 'text with a protected quotation \\" inside',
 'key7': 110142,
 'key8': 'key9',
 'key10': 'not a key0=whatewver'}

【讨论】:

    猜你喜欢
    • 2021-07-24
    • 1970-01-01
    • 2023-03-15
    • 2018-11-20
    • 2014-11-28
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    相关资源
    最近更新 更多