2015-05-28 3 views
1

У меня есть следующие данные:Как я могу выразить этот формат в EBNF?

dbCon= { 
    main = { 
     database = "db1", 
     hostname = "db1.serv.com", 
     maxConnCount = "5", 
     port = "3306", 
     slaves = [ 
      { 
       charset = "utf8", 
       client = "MYSQL", 
       compression = "true", 
       database = "db1_a", 
       hostname = "db1-a.serv.com", 
       maxConnCount = "5", 
       port = "3306", 
      } 
      { 
       charset = "utf8", 
       client = "MYSQL", 
       compression = "true", 
       database = "db1_b", 
       hostname = "db1-b.serv.com", 
       maxConnCount = "5", 
       port = "3306", 
      } 
     ] 
     username = "user-1" 
    } 
} 

Я пытаюсь использовать Grako, чтобы преобразовать это в JSON, но я не могу получить формат EBNF правильно. Вот что у меня есть:

import grako 
import json 

grammar_ebnf = """ 
    final = @:({ any } | { bracketed } | { braced }); 
    braced = '{' @:({ bracketed } | { braced } | { any }) '}' ; 
    bracketed = '[' @:({ braced } | { bracketed } | { any }) ']' ; 
    any = /^[^\[\{\]\}\n]+/ ; 
""" 

model = grako.genmodel("final", grammar_ebnf) 
with open('out.txt') as f: 
    ast = model.parse(f.read()) 
    print (json.dumps(ast, indent = 4)) 

Однако, это просто печатает:

[ 
    "dbCon = " 
] 

Где я буду неправильно? Я никогда не использовал Грако. Я просто хочу иметь возможность разбирать это во что-то полезное/доступное, не создавая статический парсер в случае изменения формата. Если формат меняется позже, кажется, проще обновить EBNF, а не перерабатывать весь парсер.

+1

Перекрестная отвечал: http://cs.stackexchange.com/questions/43060/how-can-i-represent-this-in-ebnf. –

+1

ну, ваша грамматика кажется неправильной ... но я предполагаю, что вы это уже знаете;) Некоторые вещи, которые я заметил: Нигде в вашей грамматике не появился токен для '=', который является фундаментальной частью вашего ввода. Я бы попытался добавить правило для пары ключ = значение. Я подумаю об этом чуть больше завтра. – PeterE

+2

Вам нужно использовать grako? Или вы просто хотите преобразовать это в JSON в Python? – paulotorrens

ответ

3

Трудно быть уверенным, что представляет собой настоящая грамматика только с одним примером, но, надеюсь, этого достаточно, чтобы вы могли закончить настройку, чтобы справиться с какой-либо странностью.

Нам нужен класс Semantics, чтобы иметь дело с преобразованием пар ключ/значение и их списками в словари. Тщательное использование @: в противном случае делает работу.

Как правило, при указании правил в грамматике назовите их после того, что они есть (список, dict и т. Д.), А не то, на что они похожи (скобки, в скобках). Кроме того, для начала нужно разделить вещи на множество правил. Вы всегда можете объединить их позже.

#!/usr/bin/python 

import grako 
import json 

grammar = """ 
final = kvpair; 
kvpair = key '=' value; 
key = /[^\s=]+/; 
value = @:(dict | list | string) [',']; 
list = '[' @:{ value } ']'; 
string = '"' @:/[^"]*/ '"'; 
dict = '{' @:{ kvpair } '}'; 
""" 

class Semantics(object): 
    def kvpair(self, arg): 
     key, ignore, value = arg 
     return { key: value } 
    def dict(self, arg): 
     d = { } 
     for v in arg: 
      d.update(v) 
     return d 

model = grako.genmodel("final", grammar) 

with open('out.txt') as f: 
    ast = model.parse(f.read(), semantics=Semantics()) 
    print json.dumps(ast, indent=4) 

Это производит вывод:

{ 
    "dbCon": { 
     "main": { 
      "username": "user-1", 
      "maxConnCount": "5", 
      "slaves": [ 
       { 
        "maxConnCount": "5", 
        "hostname": "db1-a.serv.com", 
        "compression": "true", 
        "database": "db1_a", 
        "charset": "utf8", 
        "port": "3306", 
        "client": "MYSQL" 
       }, 
       { 
        "maxConnCount": "5", 
        "hostname": "db1-b.serv.com", 
        "compression": "true", 
        "database": "db1_b", 
        "charset": "utf8", 
        "port": "3306", 
        "client": "MYSQL" 
       } 
      ], 
      "database": "db1", 
      "hostname": "db1.serv.com", 
      "port": "3306" 
     } 
    } 
} 
+2

Использование '' @ + :('' (а затем '' arg [0] '') в '' kvpair'' необязательно. По умолчанию ** Grako ** вернет список проанализированных элементов, если никакие украшения не добавляются к правилу. – Apalala

+1

Я не уверен, что делает '@ :(' материал даже в самом деле - я только что видел его в примере, не могли бы вы (или кто-то) дать мне версию tl; dr, когда использовать его, а когда нет? – MrDuk

+2

Семантическое действие по умолчанию, связанное с каждым правилом, состоит в том, чтобы взять все значения из правой части правила, заполнить их в списке и вернуть это значение. '@:' говорит, что семантический действие должно вместо этого возвращать значение того, к которому привязано значение '@:'. Например, в правиле строки оно указывает, что возвращаемое значение должно быть просто элементом между кавычками, а не списком, состоящим из цитаты, материал между кавычками и другая цитата. (Так '' foo'' вместо '['' ',' foo ',' '']'.) –

 Смежные вопросы

  • Нет связанных вопросов^_^