Конвертировать некрасивую строку (нестандартный формат не в формате json) в словарь - PullRequest
2 голосов
/ 18 апреля 2019

У меня есть эта строка, которую я хочу загрузить в качестве словаря, чтобы я мог получить доступ к каждому элементу.

my_str = "[
    id=xyz-111,
    abc= {
            item=[
                    {
                        a=xyz,
                        b=123,
                        c={},
                        d={
                        i=[{ip=0.0.0.0/0}]
                            },
                    }
            ]
    }
]"

В настоящее время я использую регулярное выражение (re library) для получения значения любого элемента в строке, который работает.

Есть ли более чистый способ конвертировать эту строку в словарь? Я пробовал json.loads() и ast, которые не работают.

Ожидаемый результат:

my_dict = {
    'id':'xyz-111',
    'abc': {
            'item':[
                    {
                        'a':'xyz',
                        'b':123,
                        'c':{},
                        'd':{
                        'i':[{'ip':'0.0.0.0/0'}]
                            },
                    }
            ]
    }
}

Ответы [ 2 ]

3 голосов
/ 18 апреля 2019

Ну, это довольно уродливо, но может дать вам отправную точку для создания более эффективного решения.По сути, это серия замен с первой, включающей срез и замену открывающих и закрывающих скобок на полные закрытия.Затем ast.literal_eval для преобразования в dict.

import ast
import re

s = """
[
    id=xyz-111,
    abc= {
      item=[
        {
          a=xyz,
          b=123,
          c={},
          d={
            i=[{ip=0.0.0.0/0}]
          },
        }
      ]
    }
]
"""

a = '{' + re.sub(r'=', r':', re.sub(r'\s+', '', s))[1:-1] + '}'
b = re.sub(r'([{}[\]:,])([^{}[\]:,])', r'\1"\2', a)
c = re.sub(r'([^{}[\]:,])([{}[\]:,])', r'\1"\2', b)
d = ast.literal_eval(c)

print(d)
# {'id': 'xyz-111', 'abc': {'item': [{'a': 'xyz', 'b': '123', 'c': {}, 'd': {'i': [{'ip': '0.0.0.0/0'}]}}]}}
  • a удаляет все пробелы, заменяет = на : и заменяет внешний [] на {} (Удаление пробелов является тупым инструментом, и на него нужно было бы более точно ориентироваться, если данные содержали строки с пробелами, которые необходимо было сохранить)
  • b вставляет " после скобок, точек с запятой или запятых, за которыми не следует никакихиз этих символов
  • c вставляет " перед скобками, точками с запятой или запятыми, перед которыми не стоит ни один из этих символов
  • d преобразует строку в dict, используя ast.literal_eval, что немного большепрощение, чем json.loads
0 голосов
/ 18 апреля 2019

Я согласен с вами, что обычно json.loads() будет первым выбором для принятия этого. Откуда взялась эта строка?

правильное решение

Похоже, что layer_1 некоторого фрагмента кода произвел правильно сформированный JSON, а затем layer_2 вычеркнул кавычки. Найдите layer_2 и скажите, чтобы он прекратил это делать. Или скопируйте layer_2, ваш собственный код потребляет исходные данные и лучше обрабатывать его, чтобы цитаты не потерялись.

хакерский раствор

Там, конечно, есть какая-то структура, остающаяся там, между пунктуацией и окончанием строки, так что в худшем случае стоило бы взломать UnStrip рутина, которая возвращает недостающие кавычки. В случае, например, b=123, было бы не так плохо излучать 'b':'123', как вы всегда можете опубликовать процесс, где вы рекурсивно пытаетесь преобразовать значения словаря в числа, try / except, чтобы игнорировать ошибку, если получится значение больше похоже на 'xyz', чем на целое число.

На самом деле, пример упаковки n = float(s) в try поучителен. Там может быть некоторая двусмысленность в любой данной строке ввода, с возможностью попробовать вариант A или B в качестве допустимого JSON. Может быть полезно попробовать оба варианта, завернутые в try, и верни первое, что победит, первый, который оценивает как действительный JSON.

...