Pyparsing: синтаксический анализ вложенных текстовых данных в формате JSON.

У меня есть куча вложенных данных в формате, который напоминает JSON:

company="My Company"
phone="555-5555"
people=
{
    person=
    {
        name="Bob"
        location="Seattle"
        settings=
        {
            size=1
            color="red"
        }
    }
    person=
    {
        name="Joe"
        location="Seattle"
        settings=
        {
            size=2
            color="blue"
        }
    }
}
places=
{
    ...
}

Существует много разных параметров с разными уровнями глубины - это всего лишь небольшое подмножество.

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

Есть ли какой-нибудь простой метод зацикливания или рекурсии для преобразования этих данных в дружественный к системе формат данных, такой как массивы или JSON? Я хочу избежать жесткого кодирования названий свойств. Я ищу что-то, что будет работать на Python, Java или PHP. Псевдокод тоже подойдет.

Я ценю любую помощь.

РЕДАКТИРОВАТЬ: я обнаружил библиотеку Pyparsing для Python, и, похоже, это может быть очень полезно. Я не могу найти примеры того, как использовать Pyparsing для анализа вложенных структур неизвестной глубины. Может ли кто-нибудь пролить свет на Pyparsing с точки зрения данных, которые я описал выше?

РЕДАКТИРОВАТЬ 2: Хорошо, вот рабочее решение в Pyparsing:

def parse_file(fileName):

#get the input text file
file = open(fileName, "r")
inputText = file.read()

#define the elements of our data pattern
name = Word(alphas, alphanums+"_")
EQ,LBRACE,RBRACE = map(Suppress, "={}")
value = Forward() #this tells pyparsing that values can be recursive
entry = Group(name + EQ + value) #this is the basic name-value pair


#define data types that might be in the values
real = Regex(r"[+-]?\d+\.\d*").setParseAction(lambda x: float(x[0]))
integer = Regex(r"[+-]?\d+").setParseAction(lambda x: int(x[0]))
quotedString.setParseAction(removeQuotes)

#declare the overall structure of a nested data element
struct = Dict(LBRACE + ZeroOrMore(entry) + RBRACE) #we will turn the output into a Dictionary

#declare the types that might be contained in our data value - string, real, int, or the struct we declared
value << (quotedString | struct | real | integer)

#parse our input text and return it as a Dictionary
result = Dict(OneOrMore(entry)).parseString(inputText)
return result.dump()

Это работает, но когда я пытаюсь записать результаты в файл с помощью json.dump (result), содержимое файла будет заключено в двойные кавычки. Также есть\n персонажи между многими парами данных. Я попытался подавить их в коде выше с помощьюLineEnd().suppress(), но я не должен использовать это правильно.

Хорошо, я пришел к окончательному решению, которое на самом деле превращает эти данные в JSON-дружественный Dict, как я изначально хотел. Сначала он использует Pyparsing для преобразования данных в серию вложенных списков, а затем перебирает список и преобразует его в JSON. Это позволяет мне преодолеть проблему, когда PyparsingtoDict() Метод не смог обработать, когда один и тот же объект имеет два свойства с одинаковым именем. Чтобы определить, является ли список простым списком или парой свойство / значение,prependPropertyToken метод добавляет строку__property__ перед именами свойств, когда Pyparsing обнаруживает их.

def parse_file(self,fileName):

            #get the input text file
            file = open(fileName, "r")
            inputText = file.read()


            #define data types that might be in the values
            real = Regex(r"[+-]?\d+\.\d*").setParseAction(lambda x: float(x[0]))
            integer = Regex(r"[+-]?\d+").setParseAction(lambda x: int(x[0]))
            yes = CaselessKeyword("yes").setParseAction(replaceWith(True))
            no = CaselessKeyword("no").setParseAction(replaceWith(False))
            quotedString.setParseAction(removeQuotes)
            unquotedString =  Word(alphanums+"_-?\"")
            comment = Suppress("#") + Suppress(restOfLine)
            EQ,LBRACE,RBRACE = map(Suppress, "={}")

            data = (real | integer | yes | no | quotedString | unquotedString)

            #define structures
            value = Forward()
            object = Forward() 

            dataList = Group(OneOrMore(data))
            simpleArray = (LBRACE + dataList + RBRACE)

            propertyName = Word(alphanums+"_-.").setParseAction(self.prependPropertyToken)
            property = dictOf(propertyName + EQ, value)
            properties = Dict(property)

            object << (LBRACE + properties + RBRACE)
            value << (data | object | simpleArray)

            dataset = properties.ignore(comment)

            #parse it
            result = dataset.parseString(inputText)

            #turn it into a JSON-like object
            dict = self.convert_to_dict(result.asList())
            return json.dumps(dict)



    def convert_to_dict(self, inputList):
            dict = {}
            for item in inputList:
                    #determine the key and value to be inserted into the dict
                    dictval = None
                    key = None

                    if isinstance(item, list):
                            try:
                                    key = item[0].replace("__property__","")
                                    if isinstance(item[1], list):
                                            try:
                                                    if item[1][0].startswith("__property__"):
                                                            dictval = self.convert_to_dict(item)
                                                    else:
                                                            dictval = item[1]
                                            except AttributeError:
                                                    dictval = item[1]
                                    else:
                                            dictval = item[1]
                            except IndexError:
                                    dictval = None
                    #determine whether to insert the value into the key or to merge the value with existing values at this key
                    if key:
                            if key in dict:
                                    if isinstance(dict[key], list):
                                            dict[key].append(dictval)
                                    else:
                                            old = dict[key]
                                            new = [old]
                                            new.append(dictval)
                                            dict[key] = new
                            else:
                                    dict[key] = dictval
            return dict



    def prependPropertyToken(self,t):
            return "__property__" + t[0]

Ответы на вопрос(5)

Ваш ответ на вопрос