Textblöcke gezielt auslesen

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.
Antworten
Hanss
User
Beiträge: 5
Registriert: Montag 30. Juni 2014, 15:45

Hallo Forum,

ich versuche gerade folgende aufgabe zu lösen:

Ich habe ca >1000 textdateien (mit der dateiendung .asc) in einem Ordner.
Innerhalb der Textdatei kommt irgendwann eine Zeile mit dem text ".feeder"
Anschliessend kommt in den folgenden zeilen der Textblock den ich gerne hätte.
Der Textblock endet mit der Zeile ".mount"

Ich hätte jetzt gerne alle Textblöcke nacheinander in einer einzigen neuen Textdatei, welche ich dann mit Excel weiter bearbeiten will.

alle Beispiele die ich bis jetzt gefunden habe gehen leider davon aus einen bestimmten text zu finden, und dann genau diese zeile auszugeben, das bringt mir aber leider nichts. :(

Code: Alles auswählen

#!/usr/bin/env python

import re

shakes = open("wssnt10.txt", "r")

for line in shakes:
    if re.match("(.*)(L|l)ove(.*)", line):
        print line,
Freue mich über jede Hilfestellung.

Gruß Hans

PS: die Textblöcke sind auch immer unterschiedlich Lang!
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Hanss: Das mit den regulären Ausdrücken solltest du schnell wieder vergessen. Lies besser die jeweilige Datei zeilenweise und verwerfe solange die Zeilen bis du die Startzeile siehst (also die mit ".feeder"). Anschließend muss sich dein Programm noch alle nachfolgenden Zeilen merken und zwar solange bis es die Endzeile (".mount") siehst. Das Ganze machst du für jede Datei und fasst zudem wie gewünscht die Ergebnisse in einer einzigen Datei zusammen. Es ist durchaus sinnvoll, hier mit Generator-Objekten zu arbeiten, damit man die Ergebnisse direkt in die Ausgabedatei schreiben kann. Was sind jetzt die Probleme: Der Ablauf? Die Implementierung? Beides?
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@snafu: Warum keine regulären Ausdrücke?

Code: Alles auswählen

import re
import glob
with open('output.txt', 'w') as output:
    for filename in glob.iglob('*.asc'):
        with open(filename, 'r') as inp:
            output.write(re.search(r'\.feeder\s*?\n(.*?)\.mount', inp.read(), re.DOTALL).group(1))
Was mich mehr stört, ist die Weiterverarbeitung mit Exccel :twisted:
BlackJack

@Sirius3: Zeilenweises abarbeiten finde ich auch irgendwie eleganter als die komplette Datei einzulesen und mit einem regulären Ausdruck darauf zu suchen. Ist nach Perl vielleicht auch einfach eine Immunreaktion gegen REs wenn's auch anders geht. :-)

Ungetestet:

Code: Alles auswählen

from itertools import chain, dropwhile, imap, takewhile


def iter_lines(filename):
    with open(filename, 'r') as lines:
        for line in lines:
            yield line


def process_file(filename):
    return takewhile(
        lambda line: line.rstrip() != '.mount',
        dropwhile(lambda line: line.rstrip() != '.feeder', iter_lines(filename))
    )


def process_files(filenames):
    return chain.from_iterable(imap(process_file, filenames))


def main():
    filenames = ['test.txt', 'test2.txt']
    with open('out.txt', 'w') as out_file:
        out_file.writelines(process_files(filenames))


if __name__ == '__main__':
    main()
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@BlackJack: wahrscheinlich bin ich über meine perl-Zeit noch nicht ganz hinweg:

Code: Alles auswählen

open OUT,">output.txt";
open LS,"ls *.asc|";
while(<LS>){
  open IN,"<$_";
  while(<IN>){last if($_ eq ".feeder\n");}
  while(<IN>){last if($_ eq ".mount\n"); print OUT $_;};
  close IN;
}
close LS;
close OUT;
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Sirius3 hat geschrieben:@BlackJack: wahrscheinlich bin ich über meine perl-Zeit noch nicht ganz hinweg
Sagt der Inquisition Bescheid und holt einen Exorzisten!

Beim Einsatz von Perl muss man den Rechner mit mindestens einem Liter Weihwasser vor dem Bösen schützen.
Hanss
User
Beiträge: 5
Registriert: Montag 30. Juni 2014, 15:45

Hallo und vielen Dank schon mal für die schnelle Hilfe.
Ich habe in meinem Jugendlichen Leichtsinn Python 3 Installiert, vielleicht hätte ich das erwähnen sollen.

die letzte Version von Sirius3 funktioniert ein Stück weit, bricht dann aber nach ein paar dateien mit folgender meldung ab:

Code: Alles auswählen

>>> ================================ RESTART ================================
>>> 
Traceback (most recent call last):
  File "C:\Users\hs\Desktop\ahktest\programme\forum3.py", line 6, in <module>
    output.write(re.search(r'\.feeder\s*?\n(.*?)\.mount', inp.read(), re.DOTALL).group(1))
AttributeError: 'NoneType' object has no attribute 'group'
>>> 
die Version von Blackjack startet nicht erst, mit folgender Meldung:

Code: Alles auswählen

>>> ================================ RESTART ================================
>>> 
Traceback (most recent call last):
  File "C:\Users\hs\Desktop\ahktest\forum2.py", line 1, in <module>
    from itertools import chain, dropwhile, imap, takewhile
ImportError: cannot import name 'imap'
>>> 
und die erste Version von Sirius3 startet auch nicht wegen flaschem Syntax "OUT"

vielleicht sollte ich einfach Python 2 Installieren, scheint weiter verbreitet zu sein.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Statt ``imap`` nimmst Du in Python3 einfach ``map``, welches Du auch nicht mehr aus dem ``itertools``-Paket importieren musst ;-) Damit könntest Du BlackJacks Script ganz einfach anpassen... vermutlich könnte das 2to3 auch automatisch.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
Kebap
User
Beiträge: 687
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Hanss hat geschrieben:vielleicht sollte ich einfach Python 2 Installieren, scheint weiter verbreitet zu sein.
Hallo Hans! Es schadet auch gar nicht, einfach beide 2 und 3 zu installieren, besonders wenn man anfangs viel rumprobieren will.

Abgesehen vom Ausprobieren der Codeschnipsel, was sagst du zu snafu?
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
Hanss
User
Beiträge: 5
Registriert: Montag 30. Juni 2014, 15:45

so ich habe jetzt in Blackjacks script imap durch map ersetzt, jetzt läuft es ohne Fehlermeldung, allerdings nur wenn der Dateiname test.txt lautet, jetzt muss ich nur noch herausbekommen wie ich das ändere. '*.asc' funktioniert an dieser stelle leider nicht.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hanss hat geschrieben: jetzt läuft es ohne Fehlermeldung, allerdings nur wenn der Dateiname test.txt lautet, jetzt muss ich nur noch herausbekommen wie ich das ändere.
Also *das* sollte sogar ein Nicht-Programmierer hinbekommen, sofern er den Quelltext aufmerksam liest.
BlackJack

@Hanss: Das von Sirius3 das mit einem Syntaxfehler wegen ``OUT`` abbricht ist auch kein Python sondern Perl. ;-)

Der Lauftzeitfehler mit den `NoneType` der kein `group`-Attribut hat, passiert wenn in einer Datei kein Textblock gefunden werden konnte der zwischen den beiden ”Tags” steht. Mein Programm ignoriert das einfach und liefert in dem Fall 0 Zeilen. Beide Skripte kopieren nur den ersten Textblock (sofern vorhanden). Wenn Du da ein anderes Verhalten möchtest, müsste man das bei der Programmierung irgendwie geeignet berücksichtigen.
Hanss
User
Beiträge: 5
Registriert: Montag 30. Juni 2014, 15:45

das * war nicht das problem, eher das drumherum, aber dafür machts doppelt spass wenn man es hinbekommt:

Code: Alles auswählen

from itertools import chain, dropwhile, takewhile
import glob
     
     
def iter_lines(filename):
        with open(filename, 'r') as lines:
            for line in lines:
                yield line
     
     
def process_file(filename):
        return takewhile(
            lambda line: line.rstrip() != '.mount',
            dropwhile(lambda line: line.rstrip() != '.feeder', iter_lines(filename))
        )
     
     
def process_files(filenames):
        return chain.from_iterable(map(process_file, filenames))
     
     
def main():
        filenames = glob.glob('*.asc')
        with open('out.txt', 'w') as out_file:
            out_file.writelines(process_files(filenames))
     
     
if __name__ == '__main__':
        main()
Hanss
User
Beiträge: 5
Registriert: Montag 30. Juni 2014, 15:45

nochmals vielen Dank an alle Beteiligten, jetzt läuft alles wie am Schnürchen, klasse wie schnell einem hier geholfen wird!
Antworten