Konfigurationsdatei Parsen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
PNS-Richi
User
Beiträge: 68
Registriert: Donnerstag 17. Januar 2008, 01:48

Konfigurationsdatei Parsen

Beitragvon PNS-Richi » Sonntag 1. März 2009, 13:46

Hallo,

gibt es Module für Python die das Parsen von Konfigurationsdateien erleichtern, oder habt ihr Ideen wie ich so etwas umsetzen könnte?

Beispiel:

Code: Alles auswählen

cat porn {
    domainlist /etc/...
    urllist /etc/...
    acl porn
}

acl porn {
    validtime 12:30-13:30,14:30-15:30
    redirect_url: http://www...
}


lg Richi
Benutzeravatar
hendrikS
User
Beiträge: 420
Registriert: Mittwoch 24. Dezember 2008, 22:44
Wohnort: Leipzig

Beitragvon hendrikS » Sonntag 1. März 2009, 13:53

Dauerbaustelle hat hier neulich was vorgestellt. Vielleicht hilfts.

http://www.python-forum.de/topic-17815.html
Benutzeravatar
cofi
Moderator
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Beitragvon cofi » Sonntag 1. März 2009, 14:02

Nun du könntest ConfigParser aus der StdLib oder ConfigObj(http://www.voidspace.org.uk/python/configobj.html) nehmen.

Aber du musst dann deine Config-Dateien im INI-Format schreiben.

Alternativ kannst du auch direkt Python-Code schreiben als Konfiguration.
DasIch
User
Beiträge: 2405
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Beitragvon DasIch » Sonntag 1. März 2009, 14:09

Ich bevorzuge inzwischen json als Format für Konfigurationsdateien, dass ist mit simplejson/json imho deutlich angenehmer als ConfigParser.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7471
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Beitragvon Hyperion » Sonntag 1. März 2009, 14:37

Noch ne Alternative:
http://www.python-forum.de/topic-17906.html

Interessant wäre schon die Frage, was das da für ein Format ist! Bleibt es so, ohne Verschachtelungen und Referenzen, dann sollte man sich relativ einfach einen eigenen Parser schreiben können. Ansonsten wirds natürlich schwieriger ...

Außerdem ist es eben fraglich, wieso man kein etabliertes Format nimmt - wenn man es dann wählen kann!

Ist das Format eine Vorgabe (evtl. durch ein anderes Programm), so könnte man immerhin gucken, ob es dafür einen Parser mitgeliefert gibt.
PNS-Richi
User
Beiträge: 68
Registriert: Donnerstag 17. Januar 2008, 01:48

Beitragvon PNS-Richi » Sonntag 1. März 2009, 15:10

Der Aufbau ist an die Konfigurationsdatei eines ähnlichen Programmes angelehnt. Verschachtelungen sind erst später von nöten, wenn überhaupt.

Theoretisch könnte ich ein anderes Format wählen, aber ich denke mit der Syntax habe ich es gut getroffen. Ich wollte nur wissen ob es schon etwas gibt was evtl. diese Syntax verwendet.

lg Richi
Benutzeravatar
Hyperion
Moderator
Beiträge: 7471
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Beitragvon Hyperion » Sonntag 1. März 2009, 15:19

PNS-Richi hat geschrieben:Der Aufbau ist an die Konfigurationsdatei eines ähnlichen Programmes angelehnt.

Was denn für ein ähnliches Programm? Bezogen auf "was" ähnlich?

Verschachtelungen sind erst später von nöten, wenn überhaupt.

So etwas sollte man imho schon vorher beachten ;-)

Theoretisch könnte ich ein anderes Format wählen, aber ich denke mit der Syntax habe ich es gut getroffen.

Mag sein - aber wozu das Rad neu erfinden? Ich sehe nichts, was das Format besonders machen könnte!?!

Ich wollte nur wissen ob es schon etwas gibt was evtl. diese Syntax verwendet.

lg Richi

Wenn es Deine Erfindung ist, wäre das schon ein ziemlicher Zufall ;-)
PNS-Richi
User
Beiträge: 68
Registriert: Donnerstag 17. Januar 2008, 01:48

Beitragvon PNS-Richi » Sonntag 1. März 2009, 16:48

Das Rad neu erfinden: Muss man nicht, aber Herausforderungen machen einen besser.

Was ich eigentlich meinte: Wenn es noch kein Modul zum Parsen gibt würd ichs schreiben.
Wegen der Verschachtelung bin ich noch am überlegen.

Du kannst mir gerne einen Vorschlag unterbreiten wie eine Konfigurationsdatei aussehen könnte, oder sollte :)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7471
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Beitragvon Hyperion » Sonntag 1. März 2009, 17:33

PNS-Richi hat geschrieben:Du kannst mir gerne einen Vorschlag unterbreiten wie eine Konfigurationsdatei aussehen könnte, oder sollte :)

Dazu sind doch schon genügend Vorschläge gemacht worden!

Außerdem bin ich wenig motiviert, solange Du Fragen ignorierst und nicht beantwortest! ;-)
DasIch
User
Beiträge: 2405
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Beitragvon DasIch » Sonntag 1. März 2009, 17:40

PNS-Richi hat geschrieben:Du kannst mir gerne einen Vorschlag unterbreiten wie eine Konfigurationsdatei aussehen könnte, oder sollte :)

Zum ersten sollte man nicht den Fehler machen ein eigenes Format zu erfinden wenn es schon genug gibt: json, yaml, aml, ini, xml oder zur Not auch pickle.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Beitragvon sma » Sonntag 1. März 2009, 18:23

Eigentlich ist es einfach: 1. Sprache überlegen und Grammatik definieren. 2. Überlegen, wie man zugreifen will. 3. Scanner & Parser bauen. 4. Benutzen.

Ich kann nur raten, wie die Grammatik wäre. Leider scheint man einen Scanner mit zwei Zuständen zu benötigen, da innerhalb einer Klammer nach einem Namen beliebig viel bis zum Zeilenende kommen kann. Daher kann man nicht einen simplen RE-basierten Scanner mit einem einfachen rekursiv absteigenden Parser benutzen. Ein PEG-Parser müsste es aber können...

Grammatik bis hin zu regulären Ausdrücken:

Code: Alles auswählen

config = {group}.
group = groupname ws "{" {property} ws "}".
groupname = name {name}.
property = name value.
name = ws \w+
value = ws [^\n]*\n
ws = \s*


Mein Parserrahmenwerk:

Code: Alles auswählen

import re

def word(r):
    r = re.compile(r)
    def word(s):
        m = r.match(s)
        if m: return m.group(1), s[m.end():]
    return word

def token(t): return word("()\s*" + re.escape(t))

def seq(*ps):
    def seq(s):
        r = []
        for p in ps:
            rv = p(s)
            if not rv: return None
            if rv[0]: r.append(rv[0])
            s = rv[1]
        return r, s
    return seq

def rep(p):
    def rep(s):
        r = []
        while True:
            rv = p(s)
            if not rv: return r, s
            if rv[0]: r.append(rv[0])
            s = rv[1]
    return rep


Parser:

Code: Alles auswählen

def p_name(): return word(r"\s*(\w+)")
def p_value(): return word(r"\s*([^\n]*)\n")
def p_prop(): return seq(p_name(), p_value())
def p_groupname(): return seq(p_name(), rep(p_name()))
def p_group(): return seq(p_groupname(), word(r"\s*\{"), rep(p_prop()), word(r"\s*\}"))
def p_config(): return rep(p_group())


Ich gehe davon aus, dass der `:` hinter `redirect_url` ein Fehler ist. Dann kann der Parser `p_config` die Eingabe parsen. Statt sich selbst Parser und Parserkombinatoren zu bauen, kann man z.B. PyParsing benutzen. Wäre aber lame.

Ich will mit `config["cat porn"]["acl"]` auf die Daten zugreifen können. Wie bringe ich meinen Parser dazu, mir ein dict von dicts zu bauen? Ich definiere Aktionen, die mir die Daten umwandeln und filtere damit meine Parserergebnisse.

Jeder Parser liefert nämlich die erkannten Token zurück. `word` liefert das, was im regulären Ausdruck in Klammern steht. `token` wird ignoriert. `seq` und `rep` liefern je eine Liste. `p_name` liefert mir also einen Namen als String; dito `p_value`. `p_prop` liefert mit eine Liste mit dem Namen und dem Wert. `p_groupname` liefert mit eine zweielementige Liste mit einem Namen und einer weiteren weiteren Liste mit den weiteren Namen. Hieraus macht `a_groupname` einen String. `p_group` liefert eine zweielementige Liste mit dem Gruppennamen und einer Liste mit den Listen der Properties. Diese wandelt `a_group` in ein dict um. Und `p_config` liefert nochmal eine Liste mit den Listen der Gruppen und `a_config` macht daraus nochmal ein dict.

Code: Alles auswählen

def action(p, a):
    def action(s):
        rv = p(s)
        if rv: return a(rv[0]), rv[1]
    return action

def a_groupname(v): return " ".join(v[:1] + v[1])
def a_group(v): return v[0], dict(prop for prop in v[1])
def a_config(v): return dict(v)

def p_groupname(): return action(seq(p_name(), rep(p_name())), a_groupname)
def p_group(): return action(seq(p_groupname(), token("{"), rep(p_prop()), token("}")), a_group)
def p_config(): return action(rep(p_group()), a_config)


Jetzt funktioniert dies:

Code: Alles auswählen

print p_config()("""
cat porn {
    domainlist /etc/...
    urllist /etc/...
    acl porn
}

acl porn {
    validtime 12:30-13:30,14:30-15:30
    redirect_url http://www...
}
""")[0]

Stefan

Wer ist online?

Mitglieder in diesem Forum: Bing [Bot]