2012-10-04 6 views
5

Ich habe die meiste Zeit meines Morgens damit verschwendet, dieses einfache Problem nicht zu lösen. Mit Python, ich möchte Datendateien analysieren, die wie folgt aussehen:Wie kann ich eine Textdatei basierend auf Kommentarblöcken in Python aufteilen?

# This is an example comment line, it starts with a '#' character. 
# There can be a variable number of comments between each data set. 
# Comments "go with" the data set that comes after them. 
# The first data set starts on the next line: 
0.0 1.0 
1.0 2.0 
2.0 3.0 
3.0 4.0 

# Data sets are followed by variable amounts of white space. 
# The second data set starts after this comment 
5.0 6.0 
6.0 7.0 


# One more data set. 
7.0 8.0 
8.0 9.0 

Das Python-Code, den ich das obige Beispiel in die drei „Blöcke“ würde analysieren wollen, sie als Elemente einer Liste speichern. Die einzelnen Code-Blöcke könnten selbst als Listen von Zeilen mit oder ohne Kommentarzeilen gespeichert werden. Ein handraulic Weg, dies zu tun:

#! /usr/bin/env python 

# Read in data, seperate into rows_alldata 
f=open("example") 
rows = f.read().split('\n') 
f.close() 

# Do you haz teh codez? 
datasets=[] 
datasets.append(rows[0:8]) 
datasets.append(rows[9:13]) 
datasets.append(rows[15:18]) 

Ich bin für eine allgemeinere Lösung, die eine variable Anzahl und Längen von Datensätzen unterstützt. Ich habe mehrere Katastrophen aus nicht pythonisch anmutenden Schleifen ausprobiert. Ich denke, es ist am besten, meine Frage nicht mit ihnen zu überladen; das ist Arbeit und keine "Hausaufgaben".

+0

wird immer ein Datensatz als String gespeichert werden? –

+0

Die Daten sind Rohtext, aber am Ende parse ich es zu schweben. –

+0

Weißt du was ... Wenn ich es nochmal betrachte, denke ich, dass es am einfachsten wäre, es in dem Beispiel, das ich gebe, basierend auf den Leerraumblöcken zwischen den Datensätzen zu teilen. –

Antwort

5

Verwendung groupby.

from itertools import groupby 

def contains_data(ln): 
    # just an example; there are smarter ways to do this 
    return ln[0] not in "#\n" 

with open("example") as f: 
    datasets = [[ln.split() for ln in group] 
       for has_data, group in groupby(f, contains_data) 
       if has_data] 
+0

Das funktioniert auch perfekt. –

+0

Angesichts Ihrer 'contains_data' Implementierung, möchten Sie vielleicht die Datei mit Universal Newline Support-Modus öffnen – wim

+0

@wim: Ich habe einen Kommentar eingefügt. Wie man mit Kommentaren und Leerzeilen umgeht, hängt von den OP-Dateien ab; es könnten Zeilen vorhanden sein, die nur Leerzeichen enthalten usw., die ebenfalls geparst werden müssen. –

-1
datasets = [] 
with open('example') as f: 
    for line in f: 
     if line and not line.startswith('#'): 
      datasets.append(line.split()) 
+0

Das sollte "für Linie in f" sein. –

+1

Dadurch werden die Datensätze nicht getrennt. @larsmans In der for-Schleife fehlt auch ein Doppelpunkt. –

+1

-1 tut nicht, was das OP will, Syntaxfehler, semantischer Fehler –

3
datasets = [[]] 
with open('/tmp/spam.txt') as f: 
    for line in f: 
    if line.startswith('#'): 
     if datasets[-1] != []: 
     # we are in a new block 
     datasets.append([]) 
    else: 
     stripped_line = line.strip() 
     if stripped_line: 
     datasets[-1].append(stripped_line) 
+0

Das macht genau das, was ich will. –

+1

Freut mich zu hören. Wenn Sie dort etwas numpig sind, empfehle ich Ihnen, 'np.loadtxt' zu verwenden, um Ihre Floats leichter analysieren zu können. – wim

1
import pprint 

with open("test.txt") as fh: 
    codes = [] 
    codeblock = [] 

    for line in fh: 
     stripped_line = line.strip() 

     if not stripped_line: 
      continue 

     if stripped_line.startswith("#"): 
      if codeblock: 
       codes.append(codeblock) 
       codeblock = [] 

     else: 
      codeblock.append(stripped_line.split(" ")) 

    if codeblock: 
     codes.append(codeblock) 

pprint.pprint(codes) 

Ausgang:

[[['0.0', '1.0'], ['1.0', '2.0'], ['2.0', '3.0'], ['3.0', '4.0']], 
[['5.0', '6.0'], ['6.0', '7.0']], 
[['7.0', '8.0'], ['8.0', '9.0']]] 
+0

Das funktioniert auch, obwohl ich denke, es ist nicht so elegant wie die anderen Lösungen. –

Verwandte Themen