Пользовательский парсер для файла, похожего на json python - PullRequest
0 голосов
/ 13 ноября 2018

Я пытаюсь создать синтаксический анализатор для преобразования «пользовательского» файла в JSON, чтобы мне было проще манипулировать его содержимым (для аргумента, вызовите «пользовательский» формат .qwerty).

Я уже создал Lexer, который разбивает файл на отдельные лексемы (токены), структура которых [token_type, token_value].Сейчас я изо всех сил пытаюсь разобрать лексемы в их правильных словарях, поскольку трудно вставить данные в подпод словарь, поскольку ключи не являются постоянными.А также вставлять данные в массивы, хранящиеся в словарях.

Следует отметить, что я пытаюсь последовательно проанализировать токены в реальном json-объекте python, а затем выгрузить объект json.

Пример файла можно увидеть ниже, а также то, на что должен напоминать конечный результат.

ФАЙЛ: ABC.querty

Dict_abc_1{

    Dict_abc_2{
        HeaderGUID="";
        Version_TPI="999";
        EncryptionType="0";
    }

    Dict_abc_3{
        FamilyName="John Doe";
    }

    Dict_abc_4{
        Array_abc{
            {TimeStamp="2018-11-07 01:00:00"; otherinfo="";}
            {TimeStamp="2018-11-07 01:00:00"; otherinfo="";}
            {TimeStamp="2018-11-07 01:00:00"; otherinfo="";}
            {TimeStamp="2018-11-07 02:53:57"; otherinfo="";}
            {TimeStamp="2018-11-07 02:53:57"; otherinfo="";}
        }

        Dict_abc_5{
            LastContact="2018-11-08 01:00:00";
            BatteryStatus=99;
            BUStatus=PowerOn;
            LastCallTime="2018-11-08 01:12:46";
            LastSuccessPoll="2018-11-08 01:12:46";
            CallResult=Successful;
        }
    }
}
Code=999999;

ФАЙЛ: ABC.json

{  
    "Dict_abc_1":{
        "Dict_abc_2":{
            "HeaderGUID":"",
            "Version_TPI":"999",
            "EncryptionType":"0"
        },

        "Dict_abc_3":{
            "FamilyName":"John Doe"
        },

        "Dict_abc_4":{
            "Array_abc":[
                {"TimeStamp":"2018-11-07 01:00:00", "otherinfo":""},
                {"TimeStamp":"2018-11-07 01:00:00", "otherinfo":""},
                {"TimeStamp":"2018-11-07 01:00:00", "otherinfo":""},
                {"TimeStamp":"2018-11-07 02:53:57", "otherinfo":""},
                {"TimeStamp":"2018-11-07 02:53:57", "otherinfo":""}
            ],

            "Dict_abc_5":{
                "LastContact":"2018-11-08 01:00:00",
                "BatteryStatus":99,
                "BUStatus":"PowerOn",
                "LastCallTime":"2018-11-08 01:12:46",
                "LastSuccessPoll":"2018-11-08 01:12:46",
                "CallResult":"Successful"
            }
        }
    },
    "Code":999999
}

Дополнительная информация о токене, типы токенов могут быть (с возможными значениями)

  • ИДЕНТИФИКАТОР содержатьимя идентификатора переменной
  • VARIABLE , содержащее фактические данные, принадлежащие родительскому ИДЕНТИФИКАТОРУ
  • ОПЕРАТОР равно "="
  • OPEN_BRACKET равно "{"
  • CLOSE_BRACKET равно "}"

Пример лексем ABC.querty можно увидеть ЗДЕСЬ

основной логический фрагмент main.py

def main():
    content = open_file(file_name) ## read file

    lexer = Lexer(content) ## create lexer class
    tokens = lexer.tokenize() ## create lexems as seen in pastebin

    parser = Parser(tokens).parse() ## create parser class given tokens 

    print(json.dumps(parser, sort_keys=True,indent=4, separators=(',', ': ')))

parser.py

import re

class Parser(object):
    def __init__(self, tokens):
        self.tokens = tokens
        self.token_index = 0
        self.json_object = {}
        self.current_object = {}
        self.path = [self.json_object]

    def parse(self):
        while self.token_index < len(self.tokens):

            token = self.getToken()
            token_type = token[0]
            token_value = token[1]

            print("%s \t %s" % (token_type, token_value))

            if token_type in "IDENTIFIER":
                self.increment()
                identifier_type = self.getToken()
                if identifier_type[0] in "OPEN_BRACKET":
                    identifier_two_type = self.getToken(1)
                    if identifier_two_type[0] in ["OPERATOR","IDENTIFIER"]:
                        ## make dict in current dict 
                        pass

                    elif identifier_two_type[0] in "OPEN_BRACKET":
                        ## make array in current dict 
                        pass

                elif identifier_type[0] in "OPERATOR":
                    ## insert data into current dict
                    pass


            if token_type in "CLOSE_BRACKET":
                identifier_type = self.getToken()
                if "OPEN_BRACKET" in identifier_type[0]:
                    #still in array of current dict
                    pass
                elif "IDENTIFIER" in identifier_type[0]:
                    self.changeDirectory()

                else:
                    #end script
                    pass

            self.increment()
        print(self.path)
        return self.json_object


    def changeDirectory(self):
        if len(self.path) > 0:
            self.path = self.path.pop()
            self.current_object = -1

    def increment(self):
        if self.token_index < len(self.tokens):
            self.token_index+=1

    def getToken(self, x=0):
        return self.tokens[self.token_index+x]

Дополнительная информация о разборе. В настоящее время я пытался сохранить текущий словарь в массиве путей, чтобы можно было вставлять его в словари и массивы в словарях.

Любые предложения илиРешения очень ценятся,

Спасибо.

1 Ответ

0 голосов
/ 13 ноября 2018

В прошлый раз, когда я решил эту проблему, я обнаружил, что конечный автомат очень полезен.Я хочу порекомендовать способ, когда у вас есть токены, но я не знаю, как они называются по-английски.Принцип таков: вы проходите токены и добавляете их один за другим в стек.После добавления в стек вы проверяете стек на наличие некоторых правил.Как будто вы объединяете примитивные токены в выражения, которые могут быть частью более сложных выражений.

Например, "FamilyName":"John Doe".Токены "FamilyName", : и "John Doe".

Вы добавляете первый токен в стек.stack = ["FamilyName"].Правило 1: str_obj -> E.Таким образом, вы создаете Expression(type='str', value="FamilyName") и стек теперь равен stack = [Expression].

Затем вы добавляете следующий токен.stack = [Expression, ':'].Нет правил для ':'.Иди дальше.

stack = [Expression, ':', "FamilyName"].Снова мы встречаем правило 1. Таким образом, стек становится stack = [Expression, ':', Expression].Тогда мы видим другое правило.Правило 2: E:E -> E.Используйте это как Expression(type='kv_pair, value=(Expression, Expression)).И стек становится stack=[Expression].

И если вы опишете все правила, это будет работать так.Надеюсь, это поможет.

...