String in .txt suchen und davor alles löschen

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.
Eierlikörchen
User
Beiträge: 17
Registriert: Dienstag 3. November 2020, 12:42

Hallo zusammen,

ich bin Python-Neuling und habe folgendes vor:

Ich habe eine .txt mit mehreren Zeilen. Ich möchte jede Zeile durchsuchen und sobald die Textfolge "/$" gefunden
wird, soll alles davor in der Zeile gelöscht werden.

Ich habe schon viel gegoogelt, aber komme einfach nicht weiter :-/

Danke und viele Grüße

Simone
einfachTobi
User
Beiträge: 512
Registriert: Mittwoch 13. November 2019, 08:38

Benutzeravatar
DeaD_EyE
User
Beiträge: 1240
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Code: Alles auswählen

def strip_text(input_file, output_file, pattern="/$"):
    pattern_len = len(pattern)
    with open(input_file, "rt", encoding="utf8") as fd_in, open(output_file, "wt", encoding="utf8") as fd_out:
        for line in fd_in:
            index = line.find(pattern)
            if index != -1:
                line = line[index + pattern_len:]
            fd_out.write(line)
  1. Datei zum lesen öffnen, Textmodus, utf8
  2. Datei zum schreiben neu erstellen, Textmodus, utf8
  3. Über die Zeilen der Eingabedatei iterieren (fd_in ist ein Iterator)
  4. Mit der Methode find das Muster finden. -1 == nicht gefunden
  5. Fall gefunden: Str an der Fundstelle + Länge des Musters abschneiden. Den Doppelpunkt beachten.
  6. Zeile in fd_out schreiben
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Benutzeravatar
__blackjack__
User
Beiträge: 14053
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich finde die Namen `input_file`/`fd_in` und `output_file`/`fd_out` nicht gut. Die Werte die `*_file` heissen sind gar keine Dateien sondern Datei*namen* und mit der kryptischen Abkürzung `fd` kann a) kein Anfänger etwas anfangen und ist b) in Python auch falsch, denn was in Unix & Co ein „file descriptor“ ist, also eine ganze Zahl die indirekt für eine Datei steht, ist in Python ein Dateiobjekt.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Sirius3
User
Beiträge: 18274
Registriert: Sonntag 21. Oktober 2012, 17:20

Mit Index zu arbeiten, ist meist recht kryptisch. Python hat da Methoden, die auf einem höheren Niveau arbeiten.
Das magische -1 kommt auch eher aus einer low-level Programmiersprache.

Code: Alles auswählen

    head, sep, tail = line.partition(pattern)
    if sep:
        line = tail
oder das ganze in einer Zeile mit split:

Code: Alles auswählen

line = line.split(pattern, 1)[-1]
Sirius3
User
Beiträge: 18274
Registriert: Sonntag 21. Oktober 2012, 17:20

@DeaD_EyE: Mit Index zu arbeiten, ist meist recht kryptisch. Python hat da Methoden, die auf einem höheren Niveau arbeiten.
Das magische -1 kommt auch eher aus einer low-level Programmiersprache.

Code: Alles auswählen

    head, sep, tail = line.partition(pattern)
    if sep:
        line = tail
oder das ganze in einer Zeile mit split:

Code: Alles auswählen

line = line.split(pattern, 1)[-1]
Eierlikörchen
User
Beiträge: 17
Registriert: Dienstag 3. November 2020, 12:42

Vielen Dank erstmal für Eure Antworten!! Als Anfängerin steige ich noch nicht ganz durch.
Ich habe mir jetzt mal was zusammengeschnipselt, was auch ganz gut funktioniert.
Ich starte mein "Test.py Input.txt" mit dem u.a. Code. Jetzt schneidet er für jede Zeile alles
vor "/$" ab, so wie ich es will. Er hängt die Output-Zeilen jetzt in der .txt aber unten dran. Wie schaffe ich
es, dass er den kompletten Inhalt der .txt löscht und nur die Output-Zeilen schreibt? Es soll alles
in der Input.txt stattfinden. Es soll keine zusätzliche Datei erstellt werden.

Lieben Dank für Eure Hilfe.
Simone

Code: Alles auswählen

import sys
input2 = sys.argv[1] 

with open(input2, 'r+') as textfile:

        lines = textfile.readlines()
        for l in lines:
                cut_string = l.split('/$')
                new_string = cut_string[1]
                textfile.write(new_string)             
 
textfile.close()
Sirius3
User
Beiträge: 18274
Registriert: Sonntag 21. Oktober 2012, 17:20

Eingerückt wird in Python immer mit 4 Leerzeichen pro Ebene, nicht 8.
Der Filemode 'r+' ist eigentlich nie sinnvoll. Wenn man gleichzeitig liest und schreibt, gehen Text-Dateien leicht kaputt.

Benutze sprechende Variabelnnamen. Was soll denn die 2 bei input2? l ist ein ganz schlechter Variablenname. cut_string ist eine Liste und kein String, daher sind Typen in Variablennamen selten sinnvoll. Wenn /$ mehrmals in einer Zeile vorkommen kann, dann ist der Code so nicht richtig.
Das close ist unnötig, da Du schon with benutzt.

Du mußt das in zwei Schritten machen, erst die Datei zum Lesen öffnen, dann die Daten modifizieren und dann die Datei neu zum Schreiben öffnen.
Normalerweise möchte man nicht, dass Input-Datei und Output-Datei den selben Namen haben, weil wenn was schief läuft sind die Daten weg.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1240
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

__blackjack__ hat geschrieben: Dienstag 3. November 2020, 14:26 Ich finde die Namen `input_file`/`fd_in` und `output_file`/`fd_out` nicht gut. Die Werte die `*_file` heissen sind gar keine Dateien sondern Datei*namen* und mit der kryptischen Abkürzung `fd` kann a) kein Anfänger etwas anfangen und ist b) in Python auch falsch, denn was in Unix & Co ein „file descriptor“ ist, also eine ganze Zahl die indirekt für eine Datei steht, ist in Python ein Dateiobjekt.
Ich habe mir das nicht ausgedacht, sondern diese Benennung einfach übernommen.
Wieso sollte ich jetzt andere Namen für etwas erfinden, dass bereits überall im Code ist und von jedem Anfänger in Tutorials gelesen wird?
Überall wird fd verwendet und in der Doku von Python an einer Stelle sogar nur f für ein fileobject.

Mit *_file gehe ich aber konform. Man könnte annehmen, dass es ein FileObject sein könnte, was es nicht ist.

@Sirius3 das mit partition gefällt mir am besten. Ich würde aber rpartition verwenden.

Code: Alles auswählen

def filter_pattern(text, pattern):
    return "".join(line.rpartition(pattern)[-1] for line in text.splitlines())
Hat den Vorteil, dass man die Bedingung nicht abfragen muss.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Benutzeravatar
__blackjack__
User
Beiträge: 14053
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@DeaD_EyE: Ich finde halt das man keine kryptischen Abkürzungen verwenden sollte. Die man einem Anfänger noch nicht mal richtig erklären kann, weil es ja auch nicht abgekürzt inhaltlich nicht passt. Auch wenn das irgendwo im Netz so gemacht wird. Da gibt es auch haufenweise Sternchen-Importe, ganz viel kaputten Socket-Code, und auch Code der ``global`` verwendet.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Benutzeravatar
DeaD_EyE
User
Beiträge: 1240
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Irgendwo? Überall wird fd verwendet. Wieso sollte ich jetzt für Anfänger davon abweichen?

Das ist genauso eine Konvention wie np für numpy. Es gibt kaum Code, wo numpy nicht np zugewiesen worden ist.

Das `global` und `from foo import *` schlecht sind, sollte in der PEP8 stehen und darüber braucht man nicht streiten.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Benutzeravatar
__blackjack__
User
Beiträge: 14053
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@DeaD_EyE: Ich sehe nicht das es überall verwendet wird und es ist inhaltlich halt trotzdem falsch.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Eierlikörchen
User
Beiträge: 17
Registriert: Dienstag 3. November 2020, 12:42

Ich komm nicht weiter :-/

Abgesehen von meinen "Anfänger-Bezeichnungen" für die Variablen bekomme ich es einfach nicht hin,
dass der Inhalt ersetzt und nicht hinten angefügt wird ... ich bin verzweifelt :-)

Hat jemand noch einen guten Tipp?

Danke und LG
Simone
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du musst die Datei zweimal öffnen. Einmal mit r (ohne +) zum einlesen. Und wenn alles fertig ist l mit w zum Schreiben.
Eierlikörchen
User
Beiträge: 17
Registriert: Dienstag 3. November 2020, 12:42

Hallo deets,

wenn ich die Datei (r) schließe und anschließend mit (w) wieder öffne, dann schreibt
er nur die letzte Zeile die er gefunden hat mit "/$" in die Datei. Die anderen Zeilen darüber sind
weg. Was mache ich falsch?

Danke und Gruß
Simone

Code: Alles auswählen

import sys
input2 = sys.argv[1] 

with open(input2, 'r') as textfile:
   lines = textfile.readlines()
   for l in lines:
     
     cut_string = l.split('/$')
     new_string = cut_string[1]

textfile.close()     

with open(input2, 'w') as textfile2:
      textfile2.write(new_string)
Sirius3
User
Beiträge: 18274
Registriert: Sonntag 21. Oktober 2012, 17:20

@Eierlikörchen: Du mußt schon alle new_strings wieder in einer Liste sammeln.
Warum hast Du fast alles ignoriert, was ich geschrieben habe. Gute Variablennamen sind wichtig, damit DU den Code auch verstehst.
Eierlikörchen
User
Beiträge: 17
Registriert: Dienstag 3. November 2020, 12:42

@Sirius3: Ich glaube das Problem ist, dass ich gestern mich das erstmal überhaupt mit Python beschäftigt habe :-)
Daher will ich alles verstehen und nichts ignorieren. Aber als Anfängerin ist es schwierig "reinzukommen" ...
Eierlikörchen
User
Beiträge: 17
Registriert: Dienstag 3. November 2020, 12:42

Hat noch jemand noch einen Ansatz bzw. Code der mein Problem löst?

Grüße
Simone
Benutzeravatar
__blackjack__
User
Beiträge: 14053
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Eierlikörchen: Bereits im dritten Beitrag vor zwei Tagen hat DeaD_EyE doch eine Lösung mit Erklärung was da passiert präsentiert‽ Bei der folgenden Diskussion unter uns alten Hasen ging es um die Namenswahl, nicht um den Code selbst. Warum bist *Du* denn mit *dem* Code nicht zufrieden?
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Eierlikörchen
User
Beiträge: 17
Registriert: Dienstag 3. November 2020, 12:42

Der Code funktionierte bei mir nicht. Wo liegt der Fehler?

Wie müsste ich den Code verändern, damit die Änderungen direkt in der Datei und
nicht in eine neue Datei geschrieben werden?

Danke und Grüße

Code: Alles auswählen

input_file = "Input.txt"
output_file = "Output.txt"

def strip_text(input_file, output_file, pattern="/$"):
    
    pattern_len = len(pattern)
    
    with open(input_file, "rt", encoding="utf8") as fd_in, open(output_file, "wt", encoding="utf8") as fd_out:
        for line in fd_in:
            index = line.find(pattern)
            if index != -1:
                line = line[index + pattern_len:]
            fd_out.write(line)
Antworten