2017-09-27 6 views
0

Ich habe eine Textdatei, wo die relevanten Daten (Zeilen x Spalten) nur zwischen "Start" und "Ende" -Schlüsselwörter erscheinen. Siehe unten. Ich möchte einen Code schreiben, der diese Datenteilmengen extrahieren kann. Wenn eine Zeile mit "start" beginnt, gefolgt von Daten, aber NICHT gefolgt von einem nachfolgenden "end" -Schlüsselwort, dann möchte ich diese Daten ignorieren. In meinem Beispiel unten sind data1 und data3 relevant, aber data2 ist NICHT, weil es nicht von den Schlüsselwörtern "start" und "end" eingeschlossen ist.So extrahieren Sie Datenuntergruppen aus einer Textdatendatei in Python

start 
data1 (matrix of data) /relevant because data1 is enclosed by "start" and "end" 
end 
start 
data2 (matrix of data) /not relevant because there is no "end" 
. 
start 
data3 (matrix of data) /relevant for same reason as for data1 
end 
. 
. 
and so on 

Ich dachte, ich anfangen konnte:

with open(file_path,'r') as file: 

    text = file.readlines() 
    start_indexes = [] 
    end_indexes = [] 

    for i, line in enumerate(text): 
     if line.startswith('start'): 
      start_indexes.append(i) 
     elif line.startswith('end'): 
      end_indexes.append(i) 

    for i in range(len(start_indexes)): 
     for j in range(len(end_indexes)): 
      if (start_indexes[i] < end_indexes[j] < start_indexes[i+1]): 
       print(start_indexes[i],end_indexes[j]) 

Der obige Code gibt mir die Startlinie Nummern und die Endlinie Zahlen sowohl in denen relevante Daten. Hier bin ich etwas festgefahren. Wie ziehe ich jetzt die relevanten Daten? In meinem Beispiel wäre dies data1, data3. Komme ich dem Problem den "richtigen" Weg? Sollte ich auf Pandas zurückgreifen? Gibt es einen effizienteren und direkteren Weg?

+0

Ist das Zeilenformat immer ether: 'start; Daten; Start oder Start; Daten; Ende? Bitte schreiben Sie Ihre erwartete Ausgabe für die Beispieleingabe. – wwii

Antwort

0

Verschachtelt für Loops?

Sie durchlaufen jede Kombination von Start- und Endbereichen. Sie möchten nur diejenigen, die demselben Datenelement entsprechen.

Ersetzen Sie Ihre for-Schleife mit etwas wie folgt aus:

for start, end in zip(start_indexes, end_indexes): 
    print(text[start + 1:end]) 

zip(a, b, ...) gibt eine neue Liste mit den Spalten der a, b, ..., im Wesentlichen [(a[0], b[0], ...), (a[1], b[1], ...), ...] geben. Sie gehen durch jede Spalte von start_indexes, end_indexes, geben Ihnen entsprechende Start- und Endwerte, und dann verwenden Sie Listenschnittstellenzugriff, um die Daten an diesen Zeilen abzurufen.

+0

Danke. Ich muss zip etwas besser verstehen, aber ich möchte erwähnen, dass start_indexes und end_indexes Listen mit unterschiedlichen Längen haben. Ein Datenblock wird NICHT immer von "Start" und "Ende" eingeschlossen.Nur wenn der Test erfolgreich ist, haben wir Daten, die von "Start" und "Ende" eingeschlossen sind. Wenn es einen erfolglosen Test gibt, erhalten wir in der Datendatei "Start" gefolgt von einigen unvollständigen Daten, dann NICHT gefolgt von "Ende", sondern von einem anderen "Start", wo ein zweiter Testversuch beginnt. Wenn der zweite Versuch erfolgreich ist, erhalten wir am Ende "Ende". – Murchak

+0

@Murchak Beachten Sie, dass 'zip' immer eine rechteckige Matrix zurückgibt. – HyperNeutrino

0

Ich würde einen anderen Weg verwenden, indem Sie die Datei nur sequentiell lesen (dies setzt voraus, dass die Daten in einem "Start" - "Ende" -Block nicht zu groß sind). Ich würde eine data Variable erstellen, um Daten des aktuellen Blocks zu sammeln (unabhängig davon, ob relevant oder nicht) und eine state Variable mit Zustandsübergängen.

Einige Pseudo-Python:

if state == OUTSIDE_BLOCK and line.startswith('start'): 
    state = INSIDE_BLOCK 
elif state == INSIDE_BLOCK and <line contains data>: 
    <Add to data variable> 
elif state == INSIDE_BLOCK and line.startswith('end'): 
    state = OUTSIDE_BLOCK 
    <Process collected data> 
elif state == INSIDE_BLOCK and line.startswith('start'): 
    <Throw away possibly collected data because it was irrelevant> 
0

ich persönlich regex fühlen, ist der beste Weg, um solche Situationen zu handhaben:

import re woof0='''start data1 (matrix of data) /relevant because data1 is enclosed by "start" and "end" end start data2 (matrix of data) /not relevant because there is no "end" . start data3 (matrix of data) /relevant for same reason as for data1 end . . and so on ''' re.findall(r'start(\sdata.*|\Sdata.*)\nend',woof0)

Ausgang:

['\ndata1 (matrix of data) /relevant because data1 is enclosed by "start" and "end"', '\ndata3 (matrix of data) /relevant for same reason as for data1']

+0

OP hat angegeben, dass 'start' gefolgt von' data' gefolgt von 'end' NICHT als * zu erfassender Text *. – wwii

+0

Danke Gaurav. Ich denke, Sie haben die Struktur der Daten möglicherweise falsch verstanden. Der Datenabschnitt enthält nicht das Wort data. Es ist eine beliebige Anzahl von Zeilen, bei denen jede Zeile (Zeile) eine Beobachtung ist und jede Zeile viele Spalten (Attribute) enthält. Ich bin mir nicht sicher, wie Regex helfen würde. – Murchak

+0

Verstanden! erscheinen die Daten in konsistenter Form, d. h. CSV oder Leerzeichen? –

0

Setup: einmal

s = '''start 
data1 (matrix of data) /relevant because data1 is enclosed by "start" and "end" 
end 
start 
data2 (matrix of data) /not relevant because there is no "end" 
start 
data3 (matrix of data) /relevant for same reason as for data1 
end 
start 
data4 blah 
''' 
import io 
f = io.StringIO(s) 

Iterate durch die Datei, zu testen, was jede Zeile beginnt mit; die Logik herausfinden, die benötigt wird, um gültige Datenblöcke in eine Unterliste zu setzen und sie an eine Ergebnisliste anzuhängen ...

result = [] 
sub = [] 

for line in f: 
    if line.startswith('start'): 
     # possible new data block 
     if sub: 
      # if it isn't empty it must contain 
      # a start --> data block with no end 
      result.append(sub) 
      sub = [] 
     sub = [line] 
    elif line.startswith('end'): 
     # start over 
     sub = [] 
    elif line.startswith('data'): 
     sub.append(line) 
    else: 
     # for lines that don't startwith data, start or end - if any 
     sub.append(line) 

if sub: 
    # start --> data --> EOF or end of string 
    result.append(sub) 
Verwandte Themen