Zahlen in Datei verändern

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
DiiiDiii
User
Beiträge: 24
Registriert: Donnerstag 10. Oktober 2013, 10:30

Hallo,

ich habe folgendes vor: ich öffne eine Datei und möchte nur die Zahlen verändern... Die Datei öffnen ist kein problem, aber das mit dem verändern der Zahlen ist etwas, was ich nicht weiß.
Die Datei ist wie folgt aufgebaut:

Text 123 Text
Text 123 Text
Text 123 Text
...

Nun möchte ich aber nur die Zahlen verändern... wie kann ich das machen? Ist das mit replace() möglich?

Mfg
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo DiiiDiii,
man kann im Normalfall keine Teile einer Textdatei ändern. Du mußt also die komplette Datei einlesen, Deine Zahlen ändern und die Zeilen wieder in eine Datei rausschreiben.

Grüße
Sirius
DiiiDiii
User
Beiträge: 24
Registriert: Donnerstag 10. Oktober 2013, 10:30

Danke, ja das weiß ich... nur die Frage ist wie ich die Zahlen verändere... das ist mein problem... Da weiß ich gerade leider nicht weiter
BlackJack

@DiiiDiii: Das kann man nicht so allgemein beantworten. Der geeignete Weg hängt davon ab wie die Zeilen aufgebaut sind und wie man die Zahlen identifizieren kann die ausgetauscht werden sollen. So ganz allgemein kann man natürlich ``new_text = text.replace('123', 'was anderes')`` schreiben wenn man den alten Wert der Zahlen kennt. *Das* hättest Du aber ganz einfach ausprobieren können. :-)
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

DiiiDiii hat geschrieben:Danke, ja das weiß ich... nur die Frage ist wie ich die Zahlen verändere... das ist mein problem... Da weiß ich gerade leider nicht weiter
Du könntest die Datei mit dem csv-Modul einlesen und schreiben. Zwischen Lesen und Schreiben kannst du problemlos den Wert ändern.

Versuch mal einen Ansatz und frag dann bei Problemen noch mal. Solltest du mit dem Ansatz schon Probleme haben, dann frag sofort. :D
DiiiDiii
User
Beiträge: 24
Registriert: Donnerstag 10. Oktober 2013, 10:30

Bisher ist das mein Ansatz:

Code: Alles auswählen

#!/usr/bin/python

import os
import re
import random

for root, dirs, filenames in os.walk("/root/collectd-python/superplugin/"):
                for dir in dirs:
                        pass
                for filename in filenames:
                        f = open(root +"/" + filename, "r")
                        lines = f.readlines()
                        f.close()

                        number = random.randint(500,600)
                        re.sub(r'([\d.]*\d+)', number, lines)

                        f = open(root +"/" + filename, "w")
                        f.writelines()
                        f.close()
Die Zahlen in der Datei weiß ich natürlich nicht, die sollen immer wieder verändert werden. Ich habe es mal mit re versucht, allerdings bekomme ich dann folgende Meldung:

Code: Alles auswählen

TypeError: object of type 'int' has no len()
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

DiiiDiii hat geschrieben:

Code: Alles auswählen

TypeError: object of type 'int' has no len()
Du hast noch ein paar kleine Macken in deinem Programm. Du versuchst zum Beispiel den regulären Ausdruck direkt auf der Liste arbeiten zu lassen, statt auf einem einzelnen Element der Liste.

So könnte es aussehen, obwohl es auch dort noch Verbesserungspotenzial gibt.

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-

from __future__ import print_function
from __future__ import unicode_literals

import os
import re
import random

def main():
    path = os.path.join(os.path.dirname(__file__), 'data')
    for root, dirs, filenames in os.walk(path):
        for filename in filenames:
            with open(os.path.join(root, filename), 'r') as f:
                lines = f.readlines()

            for i, line in enumerate(lines):
                number = random.randint(500, 600)
                lines[i] = re.sub(r'(\d+)', str(number), line)

            with open(os.path.join(root, filename), 'w') as f:
                f.writelines(lines)
            print(lines)

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

@DiiDii: öffne Dateien mit "with". Zum Pfade Zusammensetzen gibt es os.path.join. Du solltest die Datei nicht direkt überschreiben, sondern erst eine modifizierte Datei und diese dann umbenennen.

Code: Alles auswählen

#!/usr/bin/python
import os
import re
import random

def substitute(line):
    number = random.randint(500, 600)
    return re.sub(r'\d+', str(number), line)

def main():
    path = "/root/collectd-python/superplugin/"
    for root, _, filenames in os.walk(path):
        for filename in filenames:
            filename_in = os.path.join(root, filename)
            filename_out = filename_in+'.mod' 
            with open(filename_in, 'r') as fin, open(filename_out, 'w') as fout:
                fout.writelines(map(substitute,fin))
            os.rename(filename_out, filename_in)
 
if __name__ == '__main__':
    main()
@/me: das mit enumerate und Liste verändern ist unschön.
DiiiDiii
User
Beiträge: 24
Registriert: Donnerstag 10. Oktober 2013, 10:30

Perfekt, danke :) funktioniert beides :)
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Sirius3 hat geschrieben:@/me: das mit enumerate und Liste verändern ist unschön.
Klar ist es das. Ich wollte nur erst einmal einigermaßen dicht am ursprünglichen Code bleiben um den Threadstarter nicht abzuhängen. Ich wusste ja, dass dann anschließend noch bessere Lösungen kommen. :D
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Falls die Größe der Datei überschaubar ist und man somit keinen allzu hohen Speicherverbrauch befürchten muss, dann kann man auch den kompletten Datei-Inhalt an `re.sub()` übergeben, sowie eine Funktion mitgeben, die für jede Ersetzung aufgerufen wird. Diese würde dann die jeweils nächste Zufallszahl erzeugen. Beispiel:

Code: Alles auswählen

#!/usr/bin/env python2
import random
import re

def replace_numbers(s):
    def replacer(m):
        return str(random.randint(500, 600))
    return re.sub('\d+', replacer, s)

def main():
    text = 'bla 000 sgfsg\nblupp 000 jglfsg\nmauz 000 hsdkgfh'
    print replace_numbers(text)


if __name__ == '__main__':
    main()
Antworten