Zahlen in Datei ersetzen

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
Benutzeravatar
_johannes
User
Beiträge: 20
Registriert: Montag 19. Juni 2006, 17:37

Hallo mal wieder,

Ich hänge mal wieder an einem Problem. Passiert mir öfter da ich Python-Autodidakt bin ;-)

Also, ich möchte ein kleines Skript schreiben, das Folgendes macht:
In einer Datei in der ganz viele Zahlenkolonnen stehen (es sind Messwerte und bestimmte Ereigniskodierungen) bestimmte Zahlen ersetzen und das Ganze wieder abspeichern.

Ein Beispiel:

Code: Alles auswählen

    8.192    130051  99
    8.936    141583 141
   10.856    171343   1
   14.896    233963 195
   15.396    241713   2
   17.400    272775  99
   18.148    284369 255
   20.068    314129  14
   24.200    378175 195
   24.488    382639   1
Es geht mir dabei um die jeweils auf die 195\n folgende Zahl in der letzten Spalte. Kommt eine 2\n, soll sie durch 77\n ersetzt werden, kommt eine 1\n, durch 70\n. Alle anderen Zahlen und Leerzeichen sollen identisch zur Ursprungsdatei bleiben.

Hier mein Skriptversuch, ich versuche erstmal nur die 2er in 77er zu verwandeln:

Code: Alles auswählen

import os
import re

file1 = file('ursprungsdatei.txt')

regexwrong = r'.+195\n.+2\n'

lines = file1.read()

a = re.search(regexwrong, lines)
 if a != None:
  print re.sub(r'\ 2\n', '77\n', a.group())	
Das macht mir die erste Ersetzung richtig. Mein Problem: Wie kann ich hier iterieren? Also alle 2\n in der Datei durch 77\n ersetzen und nicht nur den ersten Treffer? Welche Schleifenkonstruktion muss/kann ich hier nehmen? Meine bisherigen Versuche mit for oder while schlugen fehl.

Hat jemand einen Tipp für mich?

Grüße,
Johannes
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Code: Alles auswählen

In [1]: text = """
   ...:     8.192    130051  99
   ...:     8.936    141583 141
   ...:    10.856    171343   1
   ...:    14.896    233963 195
   ...:    15.396    241713   2
   ...:    17.400    272775  99
   ...:    18.148    284369 255
   ...:    20.068    314129  14
   ...:    24.200    378175 195
   ...:    24.488    382639   1
   ...: """

In [2]: print text.replace('2\n', '77\n').replace('1\n', '70\n')
    8.192    130051  99
    8.936    141583 1470
   10.856    171343   70
   14.896    233963 195
   15.396    241713   77
   17.400    272775  99
   18.148    284369 255
   20.068    314129  14
   24.200    378175 195
   24.488    382639   70
Benutzeravatar
hendrikS
User
Beiträge: 420
Registriert: Mittwoch 24. Dezember 2008, 22:44
Wohnort: Leipzig

Ich würde vielleicht zeilenweise Pärchen bilden und dann drüberiterieren.
Kann man mit zip machen. Z.Bsp. so:

Code: Alles auswählen

a=[99,141,1,195,2,99,255,14,195,1]
b=zip(a,a[1:])
print b
Die Zahlen in a mußt Du natürlich durch die Zeilen erstzen.
momo
User
Beiträge: 9
Registriert: Donnerstag 19. März 2009, 17:52

Hallo !

So geht es:

Code: Alles auswählen

import os
import re

file1 = file('text.txt')
file2 = file('resultat.txt','w')
regexwrong = r'.+195\n.+2\n'

merke = 0
for line in file1.readlines():
    if merke:
        line = re.sub('2$','77',line)
        line =re.sub('1$','70',line)
        merke = 0

    else:
        if re.search('195$',line):
             merke = 1

    file2.write(line)

file1.close()
file2.close()
Gruß,

momo
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@momo:
- Es gibt True und False!
- Man sollte bei Dateinhandlings IOErrors abfangen oder eben mit "with" arbeiten.
Benutzeravatar
hendrikS
User
Beiträge: 420
Registriert: Mittwoch 24. Dezember 2008, 22:44
Wohnort: Leipzig

Hier noch mal mein Vorschlag vervollständigt. Kommentare hinsichtlich try/except sollten noch berücksichtigt werden:

Code: Alles auswählen

fd1 = open('in.txt')
fd2 = open('out.txt','w')

lines = fd1.readlines()

fd2.write(lines[0])

for l1,l2 in zip(lines,lines[1:]):
    if l1[-4:] == '195\n':

        l2=l2.replace(' 2\n','77\n').replace(' 1\n','70\n')

    fd2.write(l2)

fd1.close()
fd2.close()
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Statt

Code: Alles auswählen

if l1[-4:] == '195\n':
besser

Code: Alles auswählen

if l1.endswith('195\n'):
MfG
HWK
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Außerdem sollte man nie ein kleines L zusammen mit Zahlen benutzen. ;)
Benutzeravatar
_johannes
User
Beiträge: 20
Registriert: Montag 19. Juni 2006, 17:37

Super. Vielen Dank für Eure Hilfe.

So wie hendrikS und HWK es vorgeschlagen haben, funktioniert es bestens.
Ich bin gerade noch dabei, mir mal die Funktionsweise zu verinnerlichen.

Mal ne ganz allgemeine Frage:
Wie kommt man auf sowas? Reine Erfahrung? Habt Ihr sämtliche Pythonbefehle im Kopf?
Ich habe zwar mehrere Python-Bücher vor mir liegen, da steht das natürlich auch drin, aber ich weiss eben meist nicht nach was ich suchen soll.

Grüße, Johannes.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

_johannes hat geschrieben:Wie kommt man auf sowas? Reine Erfahrung? Habt Ihr sämtliche Pythonbefehle im Kopf?
Ich habe zwar mehrere Python-Bücher vor mir liegen, da steht das natürlich auch drin, aber ich weiss eben meist nicht nach was ich suchen soll.
Nein, alle Befehle im Kopf haben ist total unnütz. Es macht ja keinen Sinn jeden Funktion der Stdlib zu kennen wenn man auch einfach in der Dokumentation nachschauen könnte. Es hilft, sich irgendwelchen interessanten Code anzusehen und nachzuvollziehen. Oft ist es sinnvoll etwa am Interpreter-Prompt Code einzutippen und ausprobieren was man so machen könnte.
Ich fand es auch immer schön, die "What's new in Python X.Y"-Dokumente zu lesen und zu überlegen wozu die neu eingeführen Features nützlich sein könnten.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
_johannes
User
Beiträge: 20
Registriert: Montag 19. Juni 2006, 17:37

So, ich habe mir das ganze angeschaut und weiter umgesetzt, hänge aber wieder (jetzt aber an nem anderen Punkt).

Die Ersetzungen sind noch komplizierter:
Hier erstmal ein Ausschnitt aus der zu bearbeitenden Datei, damit lässt es sich leichter erklären:

Code: Alles auswählen

0.00400000 62
    0.000      3075  __
    6.160     98555   2
    8.192    130051  99
    8.936    141583 141
   10.856    171343   1
   14.896    233963 195
   15.396    241713   2
   17.400    272775  99
   18.148    284369 255
   20.068    314129  14
   24.200    378175 195
   24.488    382639   1
   26.492    413701  99
   27.224    425047 101
   29.144    454807   3
   33.532    522821 195
   34.208    533299   1
   36.220    564485  99
   36.952    575831 251
   38.872    605591   6
   42.996    669513 195
   43.924    683897   2
Es soll nun, wenn am Zeilenende eine 141 steht, die Zahl, die nach der auf die 141\n folgende 195\n steht, ersetzt werden. Wenn dort eine 1\n steht, soll diese durch 77\n ersetzt werden, wenn dort eine 2\n steht, soll diese durch 70\n ersetzt werden.
Ich muss also über Vierpäckchen iterieren. Das habe ich soweit auch hinbekommen.
Jetzt wird's noch einen Schritt komplexer und da hakt's:
Es soll jetzt nicht nur nach den 141ern geschaut werden, sondern nach allen sogenannten 'incorrect conditions' (das sind 141,142,151,152,241,242,251 und 252). Im Auschnitt oben würde also die 1\n in Zeile 24 durch 77\n ersetzt, nicht aber die in Zeile 14 und 19.

Eigentlich ganz klar, dachte ich, ich iteriere über eine Liste in der die 'incorrect conditions' stehen:

Code: Alles auswählen

incorrect = ['141\n','142\n','151\n','152\n','241\n','242\n','251\n','252\n']
#correct = ['144\n','155\n','244\n','255\n','101\n','102\n','201\n','202\n']

fd1 = open('text.txt')
fd2 = open('text.txt2','w')



lines = fd1.readlines()
for i in lines [0:3]:
	fd2.write(i)
	
for a in incorrect:
	for l1,l2,l3,l4 in zip(lines, lines[1:], lines[2:], lines[3:]):
		if l1.endswith(a) and l3.endswith('195\n'):
			l4=l4.replace(' 2\n','77\n').replace(' 1\n','70\n')
		fd2.write(l4)

fd1.close()
fd2.close()	
Leider ist das Ergebnis das gleiche, wie ohne die for a in incorrect-Schleife. Ich blicke hier irgendwie die richtige Verschachtelung nicht, oder? Ich habe schon mehrere Varianten ausprobiert… mit sehr mäßigem Erfolg.
Könnt Ihr mir sagen, wie das geht?

Grüße,
Johannes
Benutzeravatar
hendrikS
User
Beiträge: 420
Registriert: Mittwoch 24. Dezember 2008, 22:44
Wohnort: Leipzig

Laß die äußere Schleife weg und ersetze die Bedingung wie folgt:

(Ungetestet!!)

Code: Alles auswählen

if l1[-4:] in incorrect and l3.endswith('195\n'):
Außerdem noch mal Kommentare von cofi berücksichtigen. Die Variablenbezeichnung war meinerseits nicht besonders glücklich.
Benutzeravatar
_johannes
User
Beiträge: 20
Registriert: Montag 19. Juni 2006, 17:37

Super! So funzt es.

…auch wenn ich mich immer noch frage warum meine Version das nicht gemacht hat.

Auf jeden Fall vielen Dank nochmal.

Grüße,
Johannes
Antworten