So lesen und organisieren Sie Textdateien geteilt durch Schlüsselwörter

Ich arbeite an diesem Code (auf Python), der eine Textdatei liest. Die Textdatei enthält Informationen, um eine bestimmte Geometrie zu konstruieren, und sie wird durch Abschnitte unter Verwendung von Schlüsselwörtern, z. B. der Datei, getrennt:

*VERTICES 1 0 0 0 2 10 0 0 3 10 10 0 4 0 10 0 *EDGES 1 1 2 2 1 4 3 2 3 4 3 4 

Enthält die Information eines Quadrats mit Ecken bei (0,0), (0,10), (10,0), (10,10). Der Teil "* Edges" definiert die Verbindung zwischen den Ecken. Die erste Zahl in jeder Zeile ist eine ID-Nummer.

Hier ist mein Problem, die Informationen in der Textdatei sind nicht unbedingt in Ordnung, manchmal erscheint der Abschnitt "Vertices" zuerst, und einige andere Male wird der Abschnitt "Kanten" zuerst kommen. Ich habe auch andere Schlüsselwörter, also versuche ich zu vermeiden, zu wiederholen, if Aussagen zu testen, ob jede Zeile ein neues Keyword hat.

Was ich getan habe, liest die Textdatei mehrmals, jedes Mal auf der Suche nach einem anderen Stichwort:

 open file read line by line if line == *Points store all the following lines in a list until a new *command is encountered close file open file (again) read line by line if line == *Edges store all the following lines in a list until a new *command is encountered close file open file (again) ... 

Kann jemand darauf hinweisen, wie kann ich diese Keywords ohne solch ein mühsames Verfahren identifizieren? Vielen Dank.

6 Solutions collect form web for “So lesen und organisieren Sie Textdateien geteilt durch Schlüsselwörter”

Sie können die Datei einmal lesen und den Inhalt in einem Wörterbuch speichern. Da Sie die "Befehlszeilen" mit einem * bequem gekennzeichnet haben, können Sie alle Zeilen beginnend mit einem * als Wörterbuchschlüssel und alle folgenden Zeilen als die Werte für diesen Schlüssel verwenden. Sie können dies mit einer for-Schleife tun:

 with open('geometry.txt') as f: x = {} key = None # store the most recent "command" here for y in f.readlines() if y[0] == '*': key = y[1:] # your "command" x[key] = [] else: x[key].append(y.split()) # add subsequent lines to the most recent key 

Oder Sie können die Python-Liste und Wörterbuch-Verständnisse nutzen, um das Gleiche in einer Zeile zu tun:

 with open('test.txt') as f: x = {y.split('\n')[0]:[z.split() for z in y.strip().split('\n')[1:]] for y in f.read().split('*')[1:]} 

Was ich zugeben werde, ist nicht sehr nett aussieht, aber es wird die Arbeit erledigt, indem man die gesamte Datei in Klumpen zwischen '*' Zeichen aufteilt und dann neue Zeilen und Leerzeichen als Begrenzer verwendet, um die verbleibenden Chunks in Wörterbuchschlüssel und Listen von Listen aufzubrechen (Als Wörterbuchwerte).

Details zum Spalten, Strippen und Schneiden von Saiten finden Sie hier

Die Tatsache, dass sie ungeordnet sind, glaube ich, eignet sich gut für das Analysieren in ein Wörterbuch, von dem aus Sie später auf Werte zugreifen können. Ich schrieb eine Funktion, die Sie für diese Aufgabe nützlich finden können:

 features = ['POINTS','EDGES'] def parseFile(dictionary, f, features): """ Creates a format where you can access a shape feature like: dictionary[shapeID][feature] = [ [1 1 1], [1,1,1] ... ] Assumes: all features although out of order occurs in the order shape1 *feature1 . . . *featuren Assumes all possible features are in in the list features f is input file handle """ shapeID = 0 found = [] for line in f: if line[0] == '*' and found != features: found.append(line[1:]) #appends feature like POINTS to found feature = line[1:] elif line[0] == '*' and found == features: found = [] shapeID += 1 feature = line[1:] #current feature else: dictionary[shapeID][feature].append( [int(i) for i in line.split(' ')] ) return dictionary #to access the shape features you can get vertices like: for vertice in dictionary[shapeID]['POINTS']: print vertice #to access edges for edge in dictionary[shapeID]['EDGES']: print edge 

Sie sollten nur ein Wörterbuch der Abschnitte erstellen. Du könntest einen Generator benutzen, um die Datei zu lesen und jeden Abschnitt in welcher Reihenfolge sie ankommen zu lassen und ein Wörterbuch aus den Ergebnissen zu erstellen.
Hier ist ein unvollständiger Code, der dir helfen könnte:

 def load(f): with open(f) as file: section = next(file).strip() # Assumes first line is always a section data = [] for line in file: if line[0] == '*': # Any appropriate test for a new section yield section, data section = line.strip() data = [] else: data.append(list(map(int, line.strip().split()))) yield section, data 

Angenommen, die Daten oben ist in einer Datei namens data.txt :

 >>> data = dict(load('data.txt')) >>> data {'*EDGES': [[1, 1, 2], [2, 1, 4], [3, 2, 3], [4, 3, 4]], '*VERTICES': [[1, 0, 0, 0], [2, 10, 0, 0], [3, 10, 10, 0], [4, 0, 10, 0]]} 

Dann können Sie auf jeden Abschnitt verweisen, zB:

 for edge in data['*EDGES']: ... 

Angenommen, Ihre Datei heißt 'data.txt'

 from collections import defaultdict def get_data(): d = defaultdict(list) with open('data.txt') as f: key = None for line in f: if line.startswith('*'): key = line.rstrip() continue d[key].append(line.rstrip()) return d 

Die zurückgegebene defaultdict sieht wie folgt aus:

 defaultdict(list, {'*EDGES': ['1 1 2', '2 1 4', '3 2 3', '4 3 4'], '*VERTICES': ['1 0 0 0', '2 10 0 0', '3 10 10 0', '4 0 10 0']}) 

Sie greifen auf die Daten genau wie ein normales Wörterbuch zu

 d['*EDGES'] ['1 1 2', '2 1 4', '3 2 3', '4 3 4'] 

Eine gemeinsame Strategie mit dieser Art von Parsing ist es, eine Funktion zu erstellen, die die Daten einen Abschnitt zu einem Zeitpunkt liefern kann. Dann kann Ihr Top-Level-Calling-Code ziemlich einfach sein, weil es sich keine Sorgen um die Section-Logik überhaupt machen muss. Hier ist ein Beispiel mit Ihren Daten:

 import sys def main(file_path): # An example usage. for section_name, rows in sections(file_path): print('===============') print(section_name) for row in rows: print(row) def sections(file_path): # Setup. section_name = None rows = [] # Process the file. with open(file_path) as fh: for line in fh: # Section start: yield any rows we have so far, # and then update the section name. if line.startswith('*'): if rows: yield (section_name, rows) rows = [] section_name = line[1:].strip() # Otherwise, just add another row. else: row = line.split() rows.append(row) # Don't forget the last batch of rows. if rows: yield (section_name, rows) main(sys.argv[1]) 

Ein Wörterbuch ist wahrscheinlich der Weg zu gehen, dass Ihre Daten nicht bestellt wird. Sie können nach dem Lesen der Datei nach dem Namen der Datei in eine Liste zugreifen. Beachten Sie, dass das with Schlüsselwort Ihre Datei automatisch schließt.

Hier ist, wie es aussehen könnte:

 # read the data file into a simple list: with open('file.dat') as f: lines = list(f) # get the line numbers for each section: section_line_nos = [line for line, data in enumerate(lines) if '*' == data[0]] # add a terminating line number to mark end of the file: section_line_nos.append(len(lines)) # split each section off into a new list, all contained in a dictionary # with the section names as keys section_dict = {lines[section_line_no][1:]:lines[section_line_no + 1: section_line_nos[section_no + 1]] for section_no, section_line_no in enumerate(section_line_nos[:-1])} 

Du bekommst ein Wörterbuch, das so aussieht:

 {'VERTICES': ['1 0 0 0', '2 10 0 0', '3 10 10 0', '4 0 10 0'], 'EDGES': ['1 1 2', '2 1 4', '3 2 3', '4 3 4']} 

Zugriff auf jeden Abschnitt auf diese Weise:

 section_dict['EDGES'] 

Beachten Sie, dass der obige Code davon ausgeht, dass jeder Abschnitt mit * beginnt und dass keine andere Zeile mit * beginnt. Wenn das erste nicht der Fall ist, können Sie diese Änderung vornehmen:

 section_names = ['*EDGES', '*VERTICES'] section_line_nos = [line for line, data in enumerate(lines) if data.strip() in section_names] 

Beachten Sie auch, dass dieser Teil des section_dict Codes:

 lines[section_line_no][1:] 

… befreit den Stern am Anfang jedes Abschnittsnamens. Wenn dies nicht gewünscht ist, können Sie das ändern zu:

 lines[section_line_no] 

Wenn es möglich ist, wird es unerwünschte Leerzeichen in Ihrem Abschnitt Namen Zeilen, können Sie dies tun, um es loszuwerden:

 lines[section_line_no].strip()[1:] 

Ich habe das alles noch nicht getestet, aber das ist die allgemeine Idee.

  • Öffnen von Textdateien aus einer Liste in einer anderen Textdatei mit python
  • Bearbeiten einer einzelnen Zeile in einer großen Textdatei
  • Suchen von Textdateien mit verschiedenen Codierungen mit Python?
  • Konvertieren Sie tabulatorgetrennte txt-Datei in eine csv-Datei mit Python
  • Wie spalte ich eine riesige Textdatei in Python
  • Verweigern, einen Teil einer Datei in Python zu lesen
  • Fallstricke in meinem Code zum Erkennen von Textdateikodierung mit Python?
  • Ist pythonautomatisch parallelisierende IO- und CPU- oder speichergebundene Abschnitte?
  • Python: Laden von Wörtern aus Datei in einen Satz
  • Kopieren von einer Textdatei in eine andere mit Python
  • Wie springe ich zu einer bestimmten Zeile in einer riesigen Textdatei?
  • Python ist die beste Programmiersprache der Welt.