将结构化文本解析为dict

时间:2012-07-21 08:53:24

标签: python parsing

我的配置文件结构类似于简化的C语法,例如:

Main { /* some comments */
    VariableName1 = VariableValue1;
    VariableName2 = VariableValue2;

    SubSection {
        VariableName1 = VariableValue1; // inline comment
        VariableName2 = VariableValue2;
    }

    VariableName3 = "StriingValue4";
}

可以递归嵌套部分。

如何以干净,“诡异”的方式将该文件解析为dict

[编辑]

好的,我找到了pyparsing模块:)但是如果没有它,也许有人可以告诉你如何做到这一点。

[EDIT2]

由于好奇心,我想知道将来如何编写我认为简单的任务。

4 个答案:

答案 0 :(得分:2)

使用SimpleParse之类的解析器,只需输入EBNF定义即可。

您是否在某种BNF中记录了格式,不是吗?如果没有,你可以告诉下一个天才发明另一个配置格式,而不是使用json,xml,yaml或xml他无权重新发明轮子,除非他可以使用EBNF指定语法。

如果您不熟悉EBNF,可能需要一些时间来编写语法,但它会付出代价。它将使您的代码记录良好,坚如磐石,易于维护。

有关其他选项,请参阅有关Language Parsing的python wiki。

如果你尝试使用str.split或正则表达式进行一些特技表演,那么维护这段代码的每个其他开发人员都会诅咒你。

更新:

我突然意识到,如果您将SectionName替换为SectionName :;替换为,并将主要部分用一对花括号括起来,则此格式will likely to be valid json

"Name"     = JSON Grammar
"Author"   = Arsène von Wyss
"Version"  = 1.0
"About"    = 'Grammar for JSON data, following http://www.json.org/'
! and compliant with http://www.ietf.org/rfc/rfc4627

"Start Symbol" = <Json>
"Case Sensitive" = True
"Character Mapping" = 'Unicode'

! ------------------------------------------------- Sets

{Unescaped} = {All Valid} - {&1 .. &19} - ["\]
{Hex} = {Digit} + [ABCDEFabcdef]
{Digit9} = {Digit} - [0]

! ------------------------------------------------- Terminals

Number = '-'?('0'|{Digit9}{Digit}*)('.'{Digit}+)?([Ee][+-]?{Digit}+)?
String = '"'({Unescaped}|'\'(["\/bfnrt]|'u'{Hex}{Hex}{Hex}{Hex}))*'"'

! ------------------------------------------------- Rules

<Json> ::= <Object>
         | <Array>

<Object> ::= '{' '}'
           | '{' <Members> '}'

<Members> ::= <Pair>
            | <Pair> ',' <Members>

<Pair> ::= String ':' <Value>

<Array> ::= '[' ']'
          | '[' <Elements> ']'

<Elements> ::= <Value>
             | <Value> ',' <Elements>

<Value> ::= String
          | Number
          | <Object>
          | <Array>
          | true
          | false
          | null

答案 1 :(得分:2)

你需要使用这个Backus Naur表单递归地解析它,从PARSE开始:

PARSE: '{' VARASSIGN VARASSIGN [PARSE [VARASSIGN]] '}'

VARASSIGN : VARIABLENAME '=' '"' STRING '"'

VARIABLENAME: STRING

STRING: [[:alpha:]][[:alnum:]]*

因为您的结构很简单,所以您可以使用预测解析器LL(1)。

答案 2 :(得分:1)

1)编写一个tokenizer,即一个将解析字符流并将其转换为Identifiers,OpeningBrace,ClosingBrace,EqualSign和SemiColon列表的函数;注释和空格被丢弃。可以使用Regexpr来完成。

2)编写一个简单的解析器。跳过第一个Identifier和OpeningBrace。

解析器需要一个标识符,后面跟一个EqualSign或OpeningBrace,或者一个ClosingBrace。

2.1)如果EqualSign,必须跟随Identifier和SemiColon。 2.2)如果是OpeningBrace,则递归调用解析器。 2.3)如果ClosingBrace,则从递归调用返回。

在2.1的处理中,按照您喜欢的方式在dict中输入所需的数据。您可以使用封闭块的名称作为标识符的前缀,例如:

{"Main.SubSection.VariableName1": VariableValue1}

这是解析器的原型代码,在tokenizer之后调用。它会扫描字符串,其中字母代表标识符,分隔符为 = {}; ,最后一个标记必须为 $

def Parse(String, Prefix= "", Nest= 0):
    global Cursor
    if Nest == 0:
        Cursor= 0

    # Scan the input string
    while String[Cursor + 0].isalpha():
        # Identifier, starts an Assignment or a Block (Id |)
        if String[Cursor + 1] == "=":
            # Assignment, lookup (Id= | Id;)
            if String[Cursor + 2].isalpha():
                if String[Cursor + 3] == ";":
                    # Accept the assignment (Id=Id; |)
                    print Nest * " " + Prefix + String[Cursor] + "=" + String[Cursor + 2] + ";"
                    Cursor+= 4

        elif String[Cursor + 1] == "{":
            # Block, lookup (Id{ | )
            print Nest * " " + String[Cursor] + "{"
            Cursor+= 2

            # Recurse
            Parse(String, Prefix + String[Cursor - 2] + "::", Nest + 4)

        else:
            # Unexpected token
            break

    if String[Cursor + 0] == "}":
        # Block complete, (Id{...} |)
        print (Nest - 4) * " " + "}"
        Cursor+= 1
        return

    if Nest == 0 and String[Cursor + 0] == "$":
        # Done
        return

    print "Syntax error at", String[Cursor:], ":("

Parse("C{D=E;X{Y=Z;}F=G;}H=I;A=B;$")

执行时,输出:

C{
    C::D=E;
    X{
        C::X::Y=Z;
    }
    C::F=G;
}
H=I;
A=B;

证明它确实检测到了嵌套。用您喜欢的任何处理替换打印语句。

答案 3 :(得分:0)

您可以使用pyparsing为此格式编写解析器。