tags in python 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.
Antworten
donchris
User
Beiträge: 13
Registriert: Freitag 23. Januar 2009, 13:53

Wie könnte ich am einfachsten aus einer Textdatei Tags parsen und in einem array speichern ?
<VirtualHost host.some_domain.com>
ServerAdmin webmaster@host.some_domain.com
DocumentRoot /www/docs/host.some_domain.com
ServerName host.some_domain.com
ErrorLog logs/host.some_domain.com-error_log
TransferLog logs/host.some_domain.com-access_log
</VirtualHost>
mfg
donchris
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

In Python gibt es keine Arrays.

Wenn ich mich recht erinner, dann benutzt Apache für seine Konfiguration XML, wenn das stimmt, dann schau dir http://codespeak.net/lxml/ an.
donchris
User
Beiträge: 13
Registriert: Freitag 23. Januar 2009, 13:53

Es ist kein reines xml, daher ist es auch so schwer zu parsen.

Teile sind wie in einer ini
Port 80
und manche Einstellungen liegen verschachtelt vor (wie xml)
<VirtualHost host.some_domain.com>
ServerAdmin webmaster@host.some_domain.com
DocumentRoot /www/docs/host.some_domain.com
ServerName host.some_domain.com
ErrorLog logs/host.some_domain.com-error_log
TransferLog logs/host.some_domain.com-access_log
</VirtualHost>
Nun habe ich begonnen die Zeilen einzeln zu parsen und dies ist nun mein Problem. Normale einzeilige Einstellungen sollen in das "Array" - auch wenn es keines ist. Alle Mehrdimensionalen EInstellungen wie VirtualHosts sollen in Mehrdimensionale Assoziative "Arrays" - doch wie soll ich dies machen, da ja jede ZEile einzeln geparst wird. Iregend welche Vorschläge ?

Code: Alles auswählen

fobj = open("C:/httpd.conf","r")
settings = {}
vhosts = {}
anz_vhosts= count(vhosts)


for line in fobj:
    #Kommentare ausfiltern
    if line.strip().startswith('#'):
        continue
    elif line.startswith(' '):
        continue
    
    if line.startswith('<VirtualHost'):
        continue
    
    #Einzeilige Einstellungen
    zuordnung = line.split(" ") 
    try:
        settings[zuordnung[0]] = zuordnung[1]
    except IndexError:
        import pdb; pdb.set_trace 
        
fobj.close()
lg
chris
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Du hälst einfach einen State vor, denn du dann setzt wenn du auf das Anfangstag kommst und den du zurücksetzt, wenn du an das Endtag kommst. Dazu sind Stacks prädestiniert.
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Du musst dir beim Parsen den Kontext merken (irgendeine Variable) und je nach Kontext etwas anderes machen.

Code: Alles auswählen

for line in fobj:
    if "VirtualHost" in line:
        context = "vhost"
    elif "/VirtualHost" in line:
        context = ""

    if context == "vhost":
        # mach was
    elif context == "":
        # mach was anderes
Das ist natürlich nur exemplarisch und die Abfragen recht dumm, aber im Prinzip könntest du's so machen.

Gruß,
Manuel
fredistdurstig
User
Beiträge: 13
Registriert: Sonntag 18. Januar 2009, 20:08

Also wenn Du die ganze conf parsen willst und das ganze halbwegs elegant, solltest reguläre Ausdrücke verwenden.
Genau für solche Fälle sind die Dinger wie geschaffen.
Nimm dir 1-2 Tage Zeit um die Syntax zu lernen, es lohnt sich definitiv. Ich spreche da aus aktueller Erfahrung, da ich momentan ebenfalls grosse files durchparsen muss.

Das Abspeichern in Variablen sollte das geringste Problem sein.
die einzeiligen Einstellungen am besten in eine Liste speichern (die mit den []) und die assoziativen Sachen in ein Dictionary (das mit den {}). Am besten mal die Python-Doku zur Hilfe nehmen

http://docs.python.org/library/stdtypes.html#typesseq
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

fredistdurstig hat geschrieben:Also wenn Du die ganze conf parsen willst und das ganze halbwegs elegant, solltest reguläre Ausdrücke verwenden.
Genau für solche Fälle sind die Dinger wie geschaffen.
Genau dafür sind sie nicht gedacht. Sie eignen sich überhaupt nicht für verschachtelte oder kontextabhängige Strukturen (also mehr Kontext als "ab Beginn/Ende der Zeile"). Daher gibt es dafür Parser und Tokenizer. Letztere nutzen zwar öfter Reguläre Ausdrücke um Tokens zu generieren, aber Tokens haben ohne einen Parser kaum eine Bedeutung und sagen nicht aus was eigentlich in der zu parsenden Datei steht.
fredistdurstig
User
Beiträge: 13
Registriert: Sonntag 18. Januar 2009, 20:08

Naja vielleicht wäre es übertrieben, alles mit regulären Ausdrücken zu machen. Zumindest aber könnte man auf jeden Fall eine Mischung aus Parsen und Regexes verwenden.
So richtig elegant finde ich es nicht, jede Zeile mit 100 if-Abfragen nach vorhandensein irgenwelcher Strings durchzugehen.

N ganz anderer Tipp: Es gibt eine API, die sich ums Parsen von Config-Files in dieser Art kümmert, namens Augeas http://augeas.net/.
Sie ist in C geschrieben, aber es mittlerweile auch Python-Bindings dafür, die man dann schön als Modul in seinen Python-Code einbinden kann.

Unter Linux dürfte es nicht allzuschwer sein, sie zum Laufen zu bringen - hier bspw. der Link zur Debian-Seite: http://packages.debian.org/de/sid/python/python-augeas. Unter Windows wäre der Aufwand allerdings etwas höher, dort könnte man die Libraries wahrscheinlich nur mit Hilfe von Cygwin kompilieren & verwenden.
donchris
User
Beiträge: 13
Registriert: Freitag 23. Januar 2009, 13:53

Ich habe jetzt folgende Probleme:
-WIe kann ich das letzte Zeichen von einem String löschen?
-Was genau bedeutet der KeyError in Zeile 17- da soll es ja noch nichts geben .. ?!
- Irgendwelche Optimierungsvorschläge ?!

Code: Alles auswählen

import pdb;

fobj = open("C:/httpd.conf","r")
settings = {}
vhosts = {}
st_vhosts = "stop"
anz_vhosts= 1


for line in fobj:
    if line.strip().startswith('#'):
        continue
    elif line.startswith(' '):
        continue
    elif line.startswith('<VirtualHost'):
        st_vhosts = "start"
        vhosts[anz_vhosts]["Name"]= line.split(" ")[1]
        continue
    elif line.startswith('</VirtualHost>'):
        st_vhosts = "stop"
        anz_vhosts = + 1
        continue
    
    if st_vhosts == "start":
        zuordnung = line.split(" ")
        try:
            vhosts[anz_vhosts][zuordnung[0]] = zuordnung[1]
        except IndexError:
            pdb.set_trace
        continue
    elif st_vhosts == "stop":
        zuordnung = line.split(" ") 
        try:
            settings[zuordnung[0]] = zuordnung[1]
        except IndexError:
            pdb.set_trace 
            
fobj.close()
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

donchris hat geschrieben:Ich habe jetzt folgende Probleme:
-WIe kann ich das letzte Zeichen von einem String löschen?
z.B. so:

Code: Alles auswählen

In [5]: s = "Ich bin ein String"

In [6]: s = s[:-1]

In [7]: s
Out[7]: 'Ich bin ein Strin'
donchris hat geschrieben: -Was genau bedeutet der KeyError in Zeile 17- da soll es ja noch nichts geben .. ?!
wie wäre es, wenn Du ihn uns gepostet hättest?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Weitere Anmerkungen: Das Semikolon in der ersten Zeile ist völlig unnötig, ebenso wie die ``cuntinue``-Statements. Das ist hier kein C ``switch``-Statement (und auch dort würde man eher ``break`` reinsetzen).
INFACT
User
Beiträge: 385
Registriert: Freitag 5. Dezember 2008, 16:08

cofi hat geschrieben:In Python gibt es keine Arrays.
Also ich glaube, dass es doch arrays gibt:

Code: Alles auswählen

import array
ich habe mich zwar noch nicht damit beschäftigt aber es sollte funktionieren.
[b][i]ein kleines game für die die lust haben http://konaminut.mybrute.com[/i][/b]
;-)
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Mit `Python' meinte ich den Sprachumfang, nicht das komplette Konstrukt inklusive Stdlib, denn wenn man das miteinbezieht, dann ist man auch nicht fern von 3rd-Party-Modulen.
Aber das ist kleinlich.

Wesentlich wichtiger ist aber, dass es in Python keine Arrays wie in C gibt und die meint der OP - und wenn nicht die C-Arrays, dann doch die verwandter Sprachen (C++, PHP, usw.)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

cofi hat geschrieben:Wesentlich wichtiger ist aber, dass es in Python keine Arrays wie in C gibt und die meint der OP - und wenn nicht die C-Arrays, dann doch die verwandter Sprachen (C++, PHP, usw.)
Doch, wie INFACT meinte gibt es die durchaus. Und das was PHP unter einem Array versteht ist ein Listen-Dictionary-Hybrid.

Und die Sprache und die Stdlib sind teilweise ziemlich tief verflochten und die Unterscheidung in dem Kontext ist unnötig. Abgesehen davon dass der OP wohl kaum C-Style-Arrays meinte.
Antworten