3

単純化された C 構文のように構成された構成ファイルがあります。

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

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

    VariableName3 = "StriingValue4";
}

セクションは再帰的に入れ子にすることができます。

そのファイルをdictクリーンで「pythonish」な方法で解析するにはどうすればよいですか?

[編集]

OK、pyparsingモジュールを見つけました:)しかし、誰かがそれなしでこれを行う方法を教えてくれるかもしれません。

[編集2]

好奇心から、簡単なタスクを手で考えて書く方法を将来のために知りたいです。

4

4 に答える 4

2

SimpleParseのようなパーサーを使用して、EBNF 定義をフィードするだけです。

ある種の BNF で文書化された形式を持っていますね。そうでない場合は、json、xml、yaml、または xml を使用する代わりに別の構成形式を発明する次の天才に、EBNFを使用して構文を指定できない限り、車輪を再発明する権限がないことを伝えることができます。

EBNFに慣れていない場合は、文法を書くのに時間がかかるかもしれませんが、その価値はあります。これにより、コードが適切に文書化され、堅牢になり、保守が容易になります。

別のオプションについては、 Language Parsingに関する python wiki を参照してください。

str.split または正規表現を使用してスタントを実行しようとすると、このコードのメンテナンスを行う他のすべての開発者があなたをののしります。

アップデート:

を に置き換え、メインセクションを中かっこのペアで囲むと、この形式はSectionName有効な json になる可能性が高いと思いました。SectionName :;,

"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
于 2012-07-21T09:09:26.440 に答える
2

この Backus Naur 形式を使用して、PARSE から開始して再帰的に解析する必要があります。

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

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

VARIABLENAME: STRING

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

構造が簡単なので、述語パーサー LL(1) を使用できます。

于 2012-07-21T09:12:53.740 に答える
1

1) トークナイザー、つまり文字ストリームを解析し、それを識別子のリスト、OpeningBrace、ClosingBrace、EqualSign、および SemiColon に変換する関数を作成します。コメントとスペースは破棄されます。正規表現を使用して実行できます。

2) 簡単なパーサーを書きます。最初の Identifier と OpeningBrace をスキップします。

パーサーは、識別子の後に EqualSign または OpeningBrace のいずれか、または ClosingBrace が続くことを想定しています。

2.1) EqualSign の場合、識別子とセミコロンが続く必要があります。2.2) OpeningBrace の場合、パーサーを再帰的に呼び出します。2.3) ClosingBrace の場合、再帰呼び出しから戻ります。

2.1 の処理で、任意の方法で dict に目的のデータを入力します。囲んでいるブロックの名前を識別子の前に付けることができます。

{"Main.SubSection.VariableName1": VariableValue1}

これは、トークナイザーの後に呼び出されるパーサーのプロトタイプ コードです。文字が識別子を表す文字列をスキャンします。セパレータは={} です。最後のトークンは$でなければなりません。

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;

ネスティングを検出したことを証明します。print ステートメントを任意の処理に置き換えます。

于 2012-07-21T09:12:32.050 に答える
0

pyparsingを使用して、この形式のパーサーを作成できます。

于 2012-07-21T09:12:17.357 に答える