【问题标题】:Nested and escaped JSON payload to flattened dictionary - python嵌套和转义 JSON 有效负载到扁平字典 - python
【发布时间】:2021-08-31 18:46:33
【问题描述】:

我正在寻找解决我面临的问题的任何建议。这似乎是一个简单的问题,但几天后试图找到答案 - 我认为它不再是了。 我正在接收以下类似 JSON 格式的数据(StringType),并且需要将其转换为平面键值对字典。这是一个有效载荷示例:

s = """{"status": "active", "name": "{\"first\": \"John\", \"last\": \"Smith\"}", "street_address": "100 \"Y\" Street"}"""

所需的输出应如下所示:

{'status': 'active', 'name_first': 'John', 'name_last': 'Smith', 'street_address': '100 "Y" Street'}

问题是我找不到将原始字符串转换为字典的方法。如果我能做到,展平部分工作得很好。

import json
import collections
import ast


#############################################################
# Flatten complex structure into a flat dictionary
#############################################################
def flatten_dictionary(dictionary, parent_key=False, separator='_', value_to_str=True):
    """
    Turn a nested complex json into a flattened dictionary
    :param dictionary: The dictionary to flatten
    :param parent_key: The string to prepend to dictionary's keys
    :param separator: The string used to separate flattened keys
    :param value_to_str: Force all returned values to string type
    :return: A flattened dictionary
    """

    items = []

    for key, value in dictionary.items():
        new_key = str(parent_key) + separator + key if parent_key else key

        try:
            value = json.loads(value)
        except BaseException:
            value = value

        if isinstance(value, collections.MutableMapping):
            if not value.items():
                items.append((new_key,None))
            else:
                items.extend(flatten_dictionary(value, new_key, separator).items())
        elif isinstance(value, list):
            if len(value):
                for k, v in enumerate(value):
                    items.extend(flatten_dictionary({str(k): (str(v) if value_to_str else v)}, new_key).items())
            else:
                items.append((new_key,None))
        else:
            items.append((new_key, (str(value) if value_to_str else value)))

    return dict(items)


# Data sample; sting and dictionary
s = """{"status": "active", "name": "{\"first\": \"John\", \"last\": \"Smith\"}", "street_address": "100 \"Y\" Street"}"""
d =    {"status": "active", "name": "{\"first\": \"John\", \"last\": \"Smith\"}", "street_address": "100 \"Y\" Street"}

# Works for dictionary type
print(flatten_dictionary(d))

# Doesn't work for string type, for any of the below methods
e = eval(s)
# a = ast.literal_eval(s)
# j = json.loads(s)

【问题讨论】:

    标签: python json dictionary flatten


    【解决方案1】:

    试试:

    import json
    import re
    
    
    def jsonify(s):
      s = s.replace('"{','{').replace('}"','}')
      s = re.sub(r'street_address":\s+"(.+)"(.+)"(.+)"', r'street_address": "\1\2\3"',s)
      return json.loads(s)
    

    如果您必须在 Y 周围保留引号,请尝试:

    def jsonify(s):
      s = s.replace('"{','{').replace('}"','}')
      search = re.search(r'street_address":\s+"(.+)"(.+)"(.+)"',s)
      if search:
        s = re.sub(r'street_address":\s+"(.+)"(.+)"(.+)"', r'street_address": "\1\2\3"',s)
        dict_version = json.loads(s)
        dict_version['street_address'] = dict_version['street_address'].replace(search.group(2),'"'+search.group(2)+'"')
      return dict_version
    

    更普遍的尝试:

    def jsonify(s):
      pattern = r'(?<=[,}])\s*"(.[^\{\}:,]+?)":\s+"([^\{\}:,]+?)"([^\{\}:,]+?)"([^\{\}:,]+?)"([,\}])'
      s = s.replace('"{','{').replace('}"','}')
      search = re.search(pattern,s)
      matches = []
      if search:
        matches = re.findall(pattern,s)
        s = re.sub(pattern, r'"\1": "\2\3\4"\5',s)
      dict_version = json.loads(s)
      for match in matches:
        dict_version[match[0]] = dict_version[match[0]].replace(match[2],'"'+match[2]+'"')
      return dict_version
    

    【讨论】:

    • 感谢您的输入,但它不起作用,失败:RecursionError: maximum recursion depth exceeded in comparison 另外,“street_address”只是一个示例,现实世界中 JSON 有效负载的大小很大。我正在寻找更通用的解决方案。
    • 我错误地将 json.loads(jsonify(s)) 放在第一次编辑上。请仅返回 json.loads(s) 重试
    • 再次编辑以包含一个保留 Y 周围引号的版本
    • 太棒了!它适用于预定义的键,在本例中为“street_address”,但它可以是任何东西。
    • 恐怕不可能有更通用的方法,因为 json 模式可能会被字符串上不同的引号插入破坏。您可以包含其他键来进行正则表达式替换,而不仅仅是“street_address”
    猜你喜欢
    • 2018-10-30
    • 2019-01-16
    • 2019-02-04
    • 2018-11-09
    • 2019-04-24
    • 1970-01-01
    • 2011-08-27
    相关资源
    最近更新 更多