Einlesen von regelmäßig ungleichen zeilen

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.
quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

hi

ich hoffe mir kann jemand dabei helfen, ich will ein file einlesen welches folgendermaßen aussieht, wobei sich bestimmte sachen wiederholen... am ende hätte ich gerne alles in einem array wo ich dann vergleiche zwischen den werten machen kann.

im prinzip ist die datei immer folgendermaßen aufgebaut:
Eventheader... etwa alle 500 zeilen, beginnt mit einer 0
Kollisionsheader beginnt mit einer zahl größer 0 und hat 9 spalten

danach kommen je nachdem welche zahlen beim Kollisionsheader an erster und zweiter stelle standen entsprechend viele zeilen welche aus 17 spalten bestehen. wobei ich hier diese gerne in 2 verschiedene listen sortieren würde.. also angenommen im kollisionsheader stehen die zahlen 2 und 4 an erster und 2ter position, dann würden also 6 zeilen folgen, dh ich würde gerne die ersten beiden und die letzten 4 in verschied speichern.

hier nun ein beispiel eines solchen files:
0 1 197 197 0.000 0.3000E+01 0.0000E+00 0.2921E+01 0.3744E+01
2 2 2 1 1.430 0.3068E+01 0.4228E+02 0.1239E+02 0.1566E+00
144 0.14300739E+01 -0.14768857E+01 0.21676073E+01 -0.35384654E+00 0.15530421E+01 0.33218692E-01 0.46997607E-01 0.12445262E+01 0.92724424E+00 1 -1 0 0 0 0 0
265 0.14300739E+01 -0.15886200E+01 0.22127071E+01 -0.35384654E+00 0.15223111E+01 0.18339052E-02 0.15264720E+00 -0.12052195E+01 0.91737255E+00 1 1 1 0 0 0 0
144 0.14300739E+01 -0.14768857E+01 0.21676073E+01 -0.35384654E+00 0.17287987E+01 -0.63658545E-01 0.10106608E+00 -0.91667618E+00 0.14608843E+01 3 1 1 265 1 0 1001002
265 0.14300739E+01 -0.15886200E+01 0.22127071E+01 -0.35384654E+00 0.13465545E+01 0.98711142E-01 0.98578728E-01 0.95598286E+00 0.93800002E+00 1 -1 0 144 1 0 1001002
2 2 19 2 1.600 0.2847E+01 0.4397E+02 0.1658E+02 0.1752E+00
143 0.16004579E+01 -0.14565082E+01 -0.27612400E-01 -0.24624279E+00 0.14557652E+01 0.61100226E-01 -0.12188935E-01 0.11204236E+01 0.92737345E+00 1 -1 0 0 0 0 0
378 0.16004579E+01 -0.10809043E+01 0.48900578E+00 -0.24624279E+00 0.13986664E+01 -0.78483636E-01 -0.18692279E+00 -0.10490299E+01 0.90260958E+00 1 -1 0 0 0 0 0
143 0.16004579E+01 -0.14565082E+01 -0.27612400E-01 -0.24624279E+00 0.14381026E+01 -0.10665510E+00 0.12646267E+00 0.10774632E+01 0.93800002E+00 1 -1 0 378 1 0 100
378 0.16004579E+01 -0.10809043E+01 0.48900578E+00 -0.24624279E+00 0.14163290E+01 0.89271686E-01 -0.32557439E+00 -0.10060694E+01 0.93800002E+00 1 -1 0 143 1 0 100
2 2 2 3 1.812 0.2988E+01 0.4301E+02 0.8276E+01 0.1855E+00
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Und wo ist jetzt die Frage?
Das Leben ist wie ein Tennisball.
quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

naja wie ich das mache weil ich bekomm es nicht hin also ich hab es versucht mit

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf8 -*-

import string
import math
import pylab as pl

def readIN(name):
   fdata = open(name,"r")
   x=[]
   for line in fdata:
      splittn = line.split()
      if splittn[0]<0:
         x[0]=splittn[0]

        
         
   fdata.close()	
   return x[0]

x[0] = readIN("fort.15")
print float(x[0])
wobei ich mir dachte, ich überprüfe erst mal auf die 0 in der ersten zeile...
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Die Frage "Könnt ihr mir das Programm schreiben?" hast du allerdings vergessen anzuhängen ;)
Nach deiner vagen Beschreibung suchst du sowas:

Code: Alles auswählen

with open("weird_big_file.txt") as text_fd:
    for line in text_fd:
        if line.startswith("0"):
            _, lines_a, lines_b, _ = line.split(" ", 3)
           for _ in xrange(int(lines_a)):
                A.append(text_fd.next())
           for _ in xrange(int(lines_b)):
                B.append(text_fd.next())
Alles ungetestet und womöglich overengineerd

hth, Jörg
ps.: Du hättest wenigstens rausschreiben können, welche Daten/Zeilen du aus deinen Beispiel brauchst
Wir haben schon 10% vom 21. Jahrhundert hinter uns!
quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

huhu

joa also schonmal vielen dank

ich brauch alle zeilen vom kompletten event
quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

um es nochmal etwas genauer zu formulieren weil ich glaube so funktioniert das noch nicht :)

ich will wenn ein block eingelesen wurde schauen ob in den zeilen die nach dem kollisionsheader sind sich in den ersten zeilen also die ich in einem seperaten array ja speichern will bestimmte zahlenkombinationen vorkommen wenn dies ist will ich anschliessen überprüfen ob in danach folgenden zeilen welche ja in dem anderen array stehen auch bestimmte zahlen vorkommen wenn ja will ich einen counter hochzählen den ich am ende dann ausgeben will

deswegen ist es glaub ich am besten wenn ich das einlesen irgendwie so kollisionseventmäßig mache dann direkt checke und wenn die geünschten zahlen nicht drinne sind es erst garnicht speichere

hoffe du verstehst was ich meine
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Dann schreib doch dafür zunächst mal ein Grundgerüst und wir helfen dir bei konkreten Problemen.

Und übrigens:

Code: Alles auswählen

>>> TEXT = """um es nochmal etwas genauer zu formulieren weil ich glaube so funktioniert das
...  noch nicht
...
... ich will wenn ein block eingelesen wurde schauen ob in den zeilen die nach dem
...  kollisionsheader sind sich in den ersten zeilen also die ich in einem seperaten
...  array ja speichern will bestimmte zahlenkombinationen vorkommen wenn dies ist
... will ich anschliessen überprüfen ob in danach folgenden zeilen welche ja in dem
... anderen array stehen auch bestimmte zahlen vorkommen wenn ja will ich einen
... counter hochzählen den ich am ende dann ausgeben will
...
... deswegen ist es glaub ich am besten wenn ich das einlesen irgendwie so
... kollisionseventmäßig mache dann direkt checke und wenn die geünschten zahlen
... nicht drinne sind es erst garnicht speichere
...
... hoffe du verstehst was ich meine"""
>>> TEXT.count(".")
0
>>> TEXT.count(",")
0
Edit: Code umgebrochen, die Seite wurde etwas breit :roll:
Das Leben ist wie ein Tennisball.
quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

hmmm ja das problem ist dass ich es von der logik her schon garnicht mir vorstellen kann wie es funktioniert :)

also ich versuch es nochmal genauer zu verdeutlichen vlt ist es garnicht soo schwer wie ich es mir vorstelle

also ich färbe mal beispielsweise in einem event ein was ich meine:
0 1 197 197 0.000 0.3000E+01 0.0000E+00 0.2921E+01 0.3744E+01
2 2 2 1 1.430 0.3068E+01 0.4228E+02 0.1239E+02 0.1566E+00
144 0.14300739E+01 -0.14768857E+01 0.21676073E+01 -0.35384654E+00 0.15530421E+01 0.33218692E-01 0.46997607E-01 0.12445262E+01 0.92724424E+00 1 -1 0 0 0 0 0
265 0.14300739E+01 -0.15886200E+01 0.22127071E+01 -0.35384654E+00 0.15223111E+01 0.18339052E-02 0.15264720E+00 -0.12052195E+01 0.91737255E+00 1 1 1 0 0 0 0
144 0.14300739E+01 -0.14768857E+01 0.21676073E+01 -0.35384654E+00 0.17287987E+01 -0.63658545E-01 0.10106608E+00 -0.91667618E+00 0.14608843E+01 3 1 1 265 1 0 1001002
265 0.14300739E+01 -0.15886200E+01 0.22127071E+01 -0.35384654E+00 0.13465545E+01 0.98711142E-01 0.98578728E-01 0.95598286E+00 0.93800002E+00 1 -1 0 144 1 0 1001002
2 2 19 2 1.600 0.2847E+01 0.4397E+02 0.1658E+02 0.1752E+00
143 0.16004579E+01 -0.14565082E+01 -0.27612400E-01 -0.24624279E+00 0.14557652E+01 0.61100226E-01 -0.12188935E-01 0.11204236E+01 0.92737345E+00 1 -1 0 0 0 0 0
378 0.16004579E+01 -0.10809043E+01 0.48900578E+00 -0.24624279E+00 0.13986664E+01 -0.78483636E-01 -0.18692279E+00 -0.10490299E+01 0.90260958E+00 1 -1 0 0 0 0 0
143 0.16004579E+01 -0.14565082E+01 -0.27612400E-01 -0.24624279E+00 0.14381026E+01 -0.10665510E+00 0.12646267E+00 0.10774632E+01 0.93800002E+00 1 -1 0 378 1 0 100
378 0.16004579E+01 -0.10809043E+01 0.48900578E+00 -0.24624279E+00 0.14163290E+01 0.89271686E-01 -0.32557439E+00 -0.10060694E+01 0.93800002E+00 1 -1 0 143 1 0 100
ich hab hier die zahlen an position 11 im ersten event eingefärbt. es sind 2 incomming und 2 outgoing events. ich will nun überprüfen ob in einem der beiden incomming events eine 1 an postition 11 steht, wie makiert, wenn ja will ich schauen ob an position 11 der outgoing event eine 3 und eine 1 steht, wenn ja will ich einen counter hochzählen... dieses will ich dann über alle events laufen lassen und am ende mir die zahl ausgeben

hoffe man bekommt das einfach hin

hier nochmal eine datafile im past da sieht es besser aus was den zeilenumbruch angeht

http://paste.pocoo.org/show/137291/
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

ich hab hier die zahlen an position 11 im ersten event eingefärbt. es sind 2 incomming und 2 outgoing events. ich will nun überprüfen ob in einem der beiden incomming events eine 1 an postition 11 steht, wie makiert, wenn ja will ich schauen ob an position 11 der outgoing event eine 3 und eine 1 steht, wenn ja will ich einen counter hochzählen... dieses will ich dann über alle events laufen lassen und am ende mir die zahl ausgeben
Was gilt als Event? So ein 5-Zeilen-Block (wie man im pastebin sogar erkennen kann)?
Falls Ja: Werden die 5 Zeilen als

Code: Alles auswählen

Header
Incoming
Incoming
Outgoing
Outgoing
gelesen ?

Wo kommen diese Dateien eigentlich her?

hth, Jörg
Wir haben schon 10% vom 21. Jahrhundert hinter uns!
quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

hallo

jo also so ein event ist so ein 5 zeilenblock wobei die anzahl der zeilen variieren kann.. die anzahl der incomming zeilen und die der outgoing zeilen steht an position 1 und 2 des Headers

aber es sind immer nur die kollisionen die wir hier sehen... das event selber beinhaltet immer viele kollisionenund ein neues event beginnt immer mit einer zeile die genausolange ist wie die header file nur an der ersten position eine null hat

also man kann es im prinzip so schreiben, wenn wir annehmen das in der header file an position 1 und zwei jeweils eine 2 steht

EVENT
header
incomming
incomming
outgoing
outgoing

header
inc
out

etc bist irgendwann wieder ein EVENT kommt

die files stammen aus einer schwerionenkollision mir UrQMD berechnet
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Diese Datei - "collision history file" - ist ausführlich im UrQMD-Usermanual beschrieben (wer hätte DAS erwartet). Und besteht aus lauter Feldern mit fester Breite! - Ich musste allerdings recherchieren, was folgendes heißen soll:
format(i5,9e16.8,i11,2i3,i9,i5,i3,i15)
(ist mit "FORTRAN FORMAT" aber nicht soooo schwer rauszufinden).
Ich bastele noch an einer Lösung mittels state-machine rum.

hth, Jörg
Wir haben schon 10% vom 21. Jahrhundert hinter uns!
quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

wow danke vielen dank dass du dir soviel arbeit machst damit
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Okay, hier also der Versuch mit state-machine.
Bei "state == ENTRY_IN"bzw, "...ENTRY_OUT" könnte man nun filtern, welche Daten herausgelesen werden sollen.

Falls du damit was/nichts anfangen kannst, kannst du ja nochmal genau beschreiben, welche Daten/Zeilen du haben willst.

Für 'fortgeschrittene' Überlegungen wäre noch interessant, ob diese Dateien groß(>100MiB) werden.

hth, Jörg
Wir haben schon 10% vom 21. Jahrhundert hinter uns!
quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

huhu danke dir :) ich werds morgen mal testen, hab dir auch ne pm geschickt nochma ^^

die files sind wahrscheinlich mehrere gig groß und auch mehrere files
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

In meinem Code aus dem pastebin steckt ein konzeptueller Fehler: Der Fall, in dem keine 'Outgoing'-Zeilen in einem Event stehen wird nicht korrekt behandelt.
@quant: Ich habe im Moment keine Lust weiter Code zu veröffentlichen, so lange du nicht ein winziges bisschen Eigeninitiative zeigst :evil:
Falls Du Probleme hast zu verstehen, was das Programm tut (tun soll ;) ), hier mal ein bisschen Pseudocode:

Code: Alles auswählen

Für jede Zeile:
  Zustand: "Suchen":
    Fängt die Zeile mit "0" an?
      Weiter
    Fängt die Zeile mit 1-9 an?
      Die zwei Zahlen merken
      Neuer Zustand "In-zählen"
      Weiter
  Zustand "In-zählen"
    Steht in der Zeile eine gesuchte Zahl?
    Ja: Zeile merken
    'In-Zähler' verringern
    'In-Zähler'  gleich 0?
     #Was tun wenn:
     # - keine 'In'-Zeilen gezählt wurden?
     # - keine 'Out'-Zeilen kommen?
    Nächster Zustand 'Out-zählen"
    weiter
  Zustand "Out-zählen"
   ... (Fast das gleiche wie oben)
    'Out-Zähler' gleich 0?
      In- und Out-Zeilen gemerkt? jetzt Speichern/ausgeben
    Nächster Zustand "Suchen"
*hrmpf* Pseudo-code ist genauso lang wie Python-code.
hth, Jörg
Wir haben schon 10% vom 21. Jahrhundert hinter uns!
quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

huhu

also ich hab mal versucht den code zu verstehen was mir auch glaub ich gelungen ist ... nun hab ich einige probleme wo ich vlt hilfe brauch

er macht immer ärger wenn ich den flag setzen will für incoming und outgoing in zeile 28... da versteh ich das problem nicht

ab zeile 30 muss ich neu sortieren damit nur die zeilen welche nicht header und nicht event und natürlich auch nur incoming sind erfasse, irgendwie fällt mir da aber nix ein ich hab schon viel rumprobiert aber entweder läuft es garnicht oder er erfasst immer alle zeilen

Code: Alles auswählen

# /usr/bin/python
# coding:utf-8

import pprint
DATAFILE = "fort.15"
# 'enum' is sometimes dearly missed
SCAN, ENTRY_HEAD, ENTRY_IN, ENTRY_OUT = range(4)
def main():
    #to hold all extracted data,
    events = []
    state = SCAN
    with open(DATAFILE) as data_fd:
        for line in data_fd:
            if state == SCAN and line[0] == "0":
                    incoming = outgoing = 0
                    state = ENTRY_HEAD
            elif state == ENTRY_HEAD or \
                    (state == SCAN and line[0] in "123456789"):
                #prepare counter
                if line[0] in "123456789" and not line[2:9] in "0":
                    incoming,outgoing = int(line[0:1]), int(line[2:9])
                    #create new entry
                    events.append( dict(incoming=[], outgoing=[]) )
                    #local shortcuts (I'm a lazy typist) 
                    in_tmp = events[-1]["incoming"]
                    out_tmp = events[-1]["outgoing"]
                    # select next state
#                    state = ENTRY_IN if incoming else ENTRY_OUT
                    state = ENTRY_IN 
            elif state == ENTRY_IN:
                #pass
                 if line[6:22]:
                     print line[6:22]
#		 print type(int(line[156:160]))
#                in_tmp.append(int(line[156:160]))
#                incoming -= 1
#                if not incoming:
#                    state = ENTRY_OUT
#            elif state == ENTRY_OUT:
#                out_tmp.append(int(line[149:161]))
#                outgoing -= 1
#                if not outgoing:
#                    state = SCAN
            else:
#                # print "impossible state:", state
                raise IOError("file wrongly formatted")
    for data in events:
        pprint.pprint(data)
                
if "__main__" == __name__ : main()
BlackJack

@b.esser-wisser: Für Enums verwende ich meistens das hier: http://pypi.python.org/pypi/enum/

Andererseits kann man Zustandsautomaten in Python auch ganz nett mit Funktion/Methoden oder Klassen bauen. Dann hat man nicht alles in einem riesigen "switch" und keine Indirektion über "magische Zahlen" oder Enum-Objekte.
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

@BlackJack:
Meinst du das ungefähr so?

Code: Alles auswählen

class FileParser(object):
    def __init__(self, **kwargs):
        # ...
        self.next_step = self.seek_header
    def seek_header(self, line):
        # ...
        self.next_step = read_in_events
    def read_in_events(self, line):
        # ...
        self.next_step = read_out_events
    def read_out_events(self, line):
        # ...
        self.next_step = self.seek_header
    def parse_file(self):
        for line in self.file:
            self.next_step(line)
Bei "for line in file()" funktioniert ja file.tell()nicht richtig/nicht wie erwartet, wenn man sich also lieber raussschreibt, an welchen Stellen was interessantes steht, muss man die Schleife ändern :( -- das Dateiformat ist da auch blöde: Einträge mit fester Länge und unterschiedlich lange Zeilen, so dass man nicht aus der Zeilennummer den offset ausrechnen kann.

hth, Jörg
Wir haben schon 10% vom 21. Jahrhundert hinter uns!
quant
User
Beiträge: 34
Registriert: Freitag 29. Mai 2009, 12:06

hmmm also ich hab heute nochmal versucht die oben beschriebenen probleme zu lösen , aber irgendwie komm ich da nicht weiter, wenn ihr mir helfen könnt wäre echt super

lg
BlackJack

@b.esser-wisser: Jup, das Muster meinte ich.
Antworten