Seite 1 von 2
Einlesen von regelmäßig ungleichen zeilen
Verfasst: Montag 31. August 2009, 14:27
von quant
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
Verfasst: Montag 31. August 2009, 14:32
von EyDu
Hallo.
Und wo ist jetzt die Frage?
Verfasst: Montag 31. August 2009, 14:41
von quant
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...
Verfasst: Montag 31. August 2009, 14:46
von b.esser-wisser
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
Verfasst: Montag 31. August 2009, 14:55
von quant
huhu
joa also schonmal vielen dank
ich brauch alle zeilen vom kompletten event
Verfasst: Montag 31. August 2009, 15:01
von quant
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
Verfasst: Montag 31. August 2009, 15:12
von EyDu
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

Verfasst: Montag 31. August 2009, 15:23
von quant
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/
Verfasst: Montag 31. August 2009, 15:57
von b.esser-wisser
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
gelesen ?
Wo kommen diese Dateien eigentlich her?
hth, Jörg
Verfasst: Montag 31. August 2009, 16:09
von quant
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
Verfasst: Montag 31. August 2009, 17:18
von b.esser-wisser
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
Verfasst: Montag 31. August 2009, 17:22
von quant
wow danke vielen dank dass du dir soviel arbeit machst damit
Verfasst: Montag 31. August 2009, 19:07
von b.esser-wisser
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
Verfasst: Montag 31. August 2009, 21:56
von quant
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
Verfasst: Dienstag 1. September 2009, 18:47
von b.esser-wisser
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
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
Verfasst: Mittwoch 2. September 2009, 10:24
von quant
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()
Verfasst: Mittwoch 2. September 2009, 19:05
von 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.
Verfasst: Donnerstag 3. September 2009, 13:03
von b.esser-wisser
@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
Verfasst: Donnerstag 3. September 2009, 14:05
von quant
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
Verfasst: Donnerstag 3. September 2009, 18:10
von BlackJack
@b.esser-wisser: Jup, das Muster meinte ich.