Seite 1 von 1

Text aus Datei einlesen:

Verfasst: Dienstag 26. August 2008, 12:24
von baer
Hallo miteinander. Ich habe eine kurze Frage:
ich möchte aus einer sehr langen Datei die Werte a - z auslesen:

ich bin eine Zahl
a b c x y z

wobei a - z Dezimalzahlen sind.
Daher dachte ich mir das ich in der Datei "ich bin eine Zahl" schnappe, was ein eindeutiger Hinweis ist und darauf irgendwie in die nächste Zeile springen sollte um die Werte auszulesen.
Folgender Ansatz funktioniert nicht, da ich keinen Zeilenumbruch hinbekomme, unten durch \n gekennzeichnet.
Kann jemand helfen?

Code: Alles auswählen

# Idee z.B. für den ersten Wert:
re_gk = re.compile("\s*ich\s*bin\s*eine\s*Zahl\s*\n\s*(?P<gk>[0-9]*\.?[0-9]+).*", re.I)

    res=re.match(re_gk, line)
    if res != None: 
        gk = float(res.group("gk"))   
               
print "GK: %s" % gk 
Danke für eure Hilfe

Verfasst: Dienstag 26. August 2008, 12:42
von würmchen
Ist es denn unter Windows oder Linux? Bei Windows sind es zwei Zeichen die einen Zeilenumbruch darstellen, vielleicht liegt es daran...

Verfasst: Dienstag 26. August 2008, 12:52
von baer
alles unter linux!

Verfasst: Dienstag 26. August 2008, 12:54
von Rebecca
Ich wuerde das ohne RegEx machen. Einfach mit einer for-Schleife ueber alle Zeilen wandern, schauen, ob die aktuelle Zeile "ich bin eine Zahl" ist, und dann die naechste Zeile lesen. Hat auch den Vorteil, dass du nicht die komplette Datei in den Speicher laden musst.

Ungetestet:

Code: Alles auswählen

f = open(...)
prevoious_line = ""

for line in f:
    if previous_line.strip() == "Ich bin eine Zahl":
        zahlen = line.split()
    previous_line = line

Verfasst: Dienstag 26. August 2008, 13:56
von BlackJack
Alternativlösung:

Code: Alles auswählen

from __future__ import with_statement
from itertools import dropwhile

def main():
    with open('test.txt') as lines:
        lines = dropwhile(lambda x: x != 'ich bin eine Zahl\n', lines)
        lines.next()    # Skip line with sentinel text.
        a, b, c, x, y, z = map(float, lines.next().split())
    print a, b, c, x, y, z

Verfasst: Mittwoch 27. August 2008, 08:31
von baer
danke ersteinmal für die schnelle und kompetenten Antworten!
ich bin absoluter Anfänger, daher habe ich noch etwas Probleme und versuche irgendwie eine Lösung zu finden.

Code: Alles auswählen

    for line in inp:
        if line.strip() == "length of vectors":
            line = inp.next()
        print line
ich habe Häppchen aus euren Lösungen genommen und versuche es gerade so darzustellen das ich es auch verstehe.
Ich dachte das er mit obigem code die Zeile sucht, dann in die nächste Zeile springt und diese dann ausgibt. Statt dem Ausgeben würde ich dann mit RegEX die Zeile durchsuchen, aber das wäre dann nur die folge Aktion.
Aber wo ist hier gerade der Haken?

Verfasst: Mittwoch 27. August 2008, 08:35
von BlackJack
Gute Frage, wo ist er denn? Also ich meine was bekommst Du und wie unterscheidet sich das von Deiner Erwartung? Dir ist klar, dass Du im Moment alle Zeilen (ausser der mit dem Suchtext) ausgibst?

Verfasst: Mittwoch 27. August 2008, 08:47
von baer
Ich habe gehofft das nur die auf Zeile, die auf "length of vectors" folgt ausgegeben wird.

-> pattern suchen -> Zeile: length of vectors
dann line = inp.next() # Springen in die folgende Zeile
in welcher meine gesuchten Zahlen sind: a b c x y z

Das ist mein Ziel ...

Verfasst: Mittwoch 27. August 2008, 08:51
von Rebecca
BlackJack hat geschrieben:Dir ist klar, dass Du im Moment alle Zeilen (ausser der mit dem Suchtext) ausgibst?
Ich kann mir vorstellen, dass du, baer, Zeile 4 nicht so einruecken willst wie sie dort eingerueckt ist.

Verfasst: Mittwoch 27. August 2008, 08:57
von baer
Das habe ich schon ausgetestet. Ich gebe einfach mal ein par mehr Zeilen an. Wenn ich das "print line" direkt zum Beginn einrücke gibt er mir alle Zeilen aus. Deswegen habe ich gehofft das er mit dem angeführten code nur die eine Zeile ausgibt, die auf "length of vectors folgt". *urghs*

Code: Alles auswählen

for line in inp.readlines():
    res=re.match(re_vol, line)
    if res != None: 
        vol = float(res.group("vol"))
    for line in inp:
        if line.strip() == "length of vectors":
            line = inp.next()
        print line
print "Volumen: %.2f \AA^3" % vol

Verfasst: Mittwoch 27. August 2008, 10:05
von Mad-Marty
würmchen hat geschrieben:Ist es denn unter Windows oder Linux? Bei Windows sind es zwei Zeichen die einen Zeilenumbruch darstellen, vielleicht liegt es daran...
In beiden wird der newline mittels \n dargestellt aus python ...

Verfasst: Mittwoch 27. August 2008, 10:39
von BlackJack
@baer: *Was* hast Du denn mit der Einrückung ausprobiert? Das ist ja nun ein sehr übersichtliches Stück Quelltext, Du solltest mal Interpreter spielen, Dir eine kurze Textdatei ausdenken und das mal auf einem Blatt Papier durch spielen was Dein kurzer Quelltext da macht. Dann sollte eigentlich klar werden warum alle Zeilen bis auf die mit dem Suchtext ausgegeben werden.

Bei Deinem letzten Quelltext kann ich nur sagen: Nicht wild herum probieren ("programming by accident") sondern verstehen was Du da machst.

Dateien haben eine aktuelle Position bei der weitergelesen wird und bei jedem lesen einer Zeile wandert diese Position weiter. Wenn Du eine Datei einmal ausgelesen hast, ist diese Marke am Ende der Datei und man bekommt keine weiteren Zeilen mehr.

Die `readlines()`-Methode liesst alle Zeilen ein, dass heisst die innere ``for``-Schleife wird nicht ausgeführt, weil in `inp` einfach nichts mehr "drin" ist, die Datei ist ja schon komplett ausgelesen. Aber selbst wenn das funktionieren würde, würde diese Schleife für *jede* Zeile der Datei erneut ausgeführt, weil sie ja in der äusseren ``for``-Schleife steckt.

Hast Du das Tutorial aus der Dokumentation schon durchgearbeitet? Sind Dir so grundlegende Dinge wie ``for``-Schleifen wirklich klar?

Verfasst: Mittwoch 27. August 2008, 11:47
von baer
Ich bin mir noch nicht sicher, aber ich glaube das ich halbwegs damit umgehen kann.
Ich habe nochmal den entscheidenden Teil isoliert

so sieht die Ausgabe der Datei aus, wobei es ein iteratives verfahren ist und ich nur den letzten hit benötige!

length of vectors
7.579211058 7.579211058 7.579211058 0.131939854 0.131939854 0.131939854

Dann das Skript

Code: Alles auswählen

#!/usr/bin/env python
import sys

try:
    inp = open("OUTCAR","r")
except:
    inp = None                
    print "Datei nicht vorhanden"
    sys.exit()

for line in inp.readlines():     
    previousline = ""              
    if previousline.strip() == "length of vectors": 
        inp.next()                   
        previousline = line 
print line
inp.close()
*grübel* was mache ich nur falsch ... *grübel*

Verfasst: Mittwoch 27. August 2008, 12:14
von baer
Da gibts noch viel zu lernen, aber ich habe es nun so gelöst:

Code: Alles auswählen

#!/usr/bin/env python
import sys

try:
    inp = open("OUTCAR","r")
except:
    inp = None
    print "Datei nicht vorhanden"
    sys.exit()

previousline = ""
for line in inp.readlines():
    line = line.strip()
    if  previousline == "length of vectors":
        actual_line = line
    previousline = line 
print actual_line
inp.close()
was auch zu funktionieren scheint! Danke auf jeden Fall schonmal für Eure Beiträge!

Verfasst: Mittwoch 27. August 2008, 17:19
von BlackJack
Das ``except`` ohne konkrete Ausnahme ist nicht schön. Damit wird bei *jeder* Ausnahme ausgegeben, dass die Datei nicht vorhanden sei, auch wenn das gar nicht stimmt. Zum Beispiel auch wenn das Programm an der Stelle mit CTRL-C abgebrochen wurde, kein Speicher mehr verfügbar ist, oder Du Dich in dem ``try``-Block irgendwo bei einem Namen vertippt hast und damit einen `NameError` oder einen `AttributeError` provozierst. Solche Fehler können dann sehr schwer zu finden sein weil wichtige Informationen einfach verschluckt bzw. durch eine irreführende Fehlermeldung ersetzt werden.

Den Aufruf von `readlines()` kannst Du Dir sparen und statt dessen einfach direkt über `inp` iterieren. Dann muss nicht die gesamte Datei auf einmal in den Speicher geladen werden.