Datei mit neuem Namen abspeichern

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.
Phobit
User
Beiträge: 185
Registriert: Freitag 4. Mai 2018, 18:13

Hallo,
ich möchte dass mein Programm eine Datei nimmt (in dem Fall jetzt mal "test1.txt", kann aber variieren), da was reinschreibt etc (das ist egal) und sie später "mit einer zahl höher", also "test2.txt" abspeichert.
Das Problem ist, man weiß vorher nicht wie lang der Dateiname ist bzw wo in dem Namen die Zahl steht.

Also müsste ich irgendwie rausfinden, an welcher Stelle die Zahl steht, diese Stelle ersetzen und dann alles wieder als Name zusammensetzen.

Zum scannen nach zahlen hab ich diesen Code:

Code: Alles auswählen

testString = "text mit zahl 1 und auch ne 12 und ne 14"
zahlen = re.findall('([0-9]*)', testString)
print(zahlen)
Wüsste jemand, wie es möglich wäre nicht den ganzen String auf einmal abzuchecken, sondern Zeichen für Zeichen, bis er bei "1" angelangt ist? Und dieses "1" dann ggf durch "2" zu ersetzen?
Mir egal, ob der Code schön ist oder nicht.
Hauptsache er funkt!
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

Hey,

habe eine Möglichkeit, geht bestimmt noch einfacher bzw. eleganter, aber es funktioniert (mehr erwartest du ja laut Signatur nicht :P) .

Code: Alles auswählen

test_string = "text mit zahl 1 und auch ne 12 und ne 14"

ZAHLEN = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']

print(test_string)
for i, x in enumerate(test_string):
    if x in ZAHLEN :
        string_in_list = list(test_string)
        neue_zahl = int(string_in_list[i]) + 1
        string_in_list[i] = str(neue_zahl)
        new_string = "".join(string_in_list)
        print(new_string)
        break

Mit freundlichen Grüßen

Jankie
Phobit
User
Beiträge: 185
Registriert: Freitag 4. Mai 2018, 18:13

Ahh super, vielen vielen Dank :-)

Jap, da trifft die Signatur zu, hauptsache es macht was es soll ;-)
Mir egal, ob der Code schön ist oder nicht.
Hauptsache er funkt!
Benutzeravatar
__blackjack__
User
Beiträge: 14042
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Jankie: Mach mal aus der 1 eine 10 und sag dann noch mal das funktioniert. :-)
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
nezzcarth
User
Beiträge: 1757
Registriert: Samstag 16. April 2011, 12:47

Phobit hat geschrieben: Freitag 5. April 2019, 13:58 Jap, da trifft die Signatur zu, hauptsache es macht was es soll ;-)
Ich will ja keine schlechte Stimmung verbreiten, aber ich glaube mit dieser Haltung wirst du mit Python eher nicht glücklich. Für mich (und nach meiner Wahrnehmung auch für viele andere Python-Programmierer) zeichnet sich diese Sprache gerade dadurch aus, dass man versucht, sauberen, gut lesbaren Code zu schreiben, der eben nicht einfach "nur funktionieren" soll. Für Quick & Dirty ist man bei anderen Sprachen vielleicht besser beraten.
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

Ohh, so weit hab ich nicht gedacht, peinlich.


neuer Versuch:

Code: Alles auswählen

import re
text = "text mit zahl 111 und auch ne 12 und ne 134364 1,3 1.5 2,56 78.545"
print(text)
liste_alle_zahlen = re.findall('\d+[,.]\d+|\d+', text)
liste_jedes_wort_einzeln = text.split()
for i, x in enumerate(liste_jedes_wort_einzeln):
    if x == liste_alle_zahlen[0]:
        liste_jedes_wort_einzeln[i] = str(int(liste_alle_zahlen[0]) + 1)
        new_string = " ".join(liste_jedes_wort_einzeln)
        print(new_string)
        break
Mit freundlichen Grüßen

Jankie
Benutzeravatar
__blackjack__
User
Beiträge: 14042
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Jankie: Wenn Du das `re`-Modul in der Lösung verwendest, dann ist das jetzt aber sehr umständlich gelöst, denn es gibt ja auch `re.sub()` wo man als zweites Argument eine Funktion übergeben kann, die das Match-Objekt übergeben bekommt und mit der Information dann die Zeichenkette durch die der Match ersetzt werden soll berechnen kann.

Auch bei der gezeigten Lösung ist es unnötig kompliziert `liste_alle_zahlen` zu erstellen, wenn man sowieso nur die erste braucht. Da würde ein `re.search()` reichen. Und den aufgespaltenen `text` bräuchte man dann auch nicht mehr, denn so ein Match-Objekt weiss ja auch an welchem Index es auf den `text` passt.
Was soll das mit ',' und '.'? Hast Du mal ausprobiert was passiert wenn so ein Treffer vor einem ohne im `text` vorkommt?

Ausserdem wäre es vielleicht wünschenswert wenn der Code auch mit dem Fall sinnvoll umgehen könnte das *keine* Ziffernfolge im `text` vorkommt.

Wenn Du das in eine Funktion verpackst, wäre es zudem einfacher den Ansatz mal mit mehr als einem Testfall auszuprobieren.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Phobit
User
Beiträge: 185
Registriert: Freitag 4. Mai 2018, 18:13

nezzcarth hat geschrieben: Freitag 5. April 2019, 14:49
Phobit hat geschrieben: Freitag 5. April 2019, 13:58 Jap, da trifft die Signatur zu, hauptsache es macht was es soll ;-)
Ich will ja keine schlechte Stimmung verbreiten, aber ich glaube mit dieser Haltung wirst du mit Python eher nicht glücklich. Für mich (und nach meiner Wahrnehmung auch für viele andere Python-Programmierer) zeichnet sich diese Sprache gerade dadurch aus, dass man versucht, sauberen, gut lesbaren Code zu schreiben, der eben nicht einfach "nur funktionieren" soll.
Keine Angst, tust du nicht ^^

Ich verstehe was du meinst... Aber als Schüler-Hobby-Programmierer und jemand, der seine Codes selten bzw nicht für openSource schreibt, brauch ich die Schöne Struktur nicht wirklich...Wenn ich mit dem Programm fertig bin, schau ich natürlich, wo geht was weg, was geht kürzer, was ist hässlich... Aber erstmal ist mir immer wichtig, dass es funktioniert ^^ Das das vllt nicht grad später beruflich der beste Ansatz ist, ist mir bewusst, aber wie gesagt, Hobby Programmierer ^^
Für Quick & Dirty ist man bei anderen Sprachen vielleicht besser beraten.
Wenn ich mir anschaue, wie die JavaCodes meiner Klassenkameraden, die Informatik wirklich nur genommen haben, weil die alternative Französisch wäre, aussehen, ist mein Code noch "Slow & Beautiful" ^^
Mir egal, ob der Code schön ist oder nicht.
Hauptsache er funkt!
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

__blackjack__ hat geschrieben: Freitag 5. April 2019, 16:14 @Jankie: Wenn Du das `re`-Modul in der Lösung verwendest, dann ist das jetzt aber sehr umständlich gelöst, denn es gibt ja auch `re.sub()` wo man als zweites Argument eine Funktion übergeben kann, die das Match-Objekt übergeben bekommt und mit der Information dann die Zeichenkette durch die der Match ersetzt werden soll berechnen kann.

Auch bei der gezeigten Lösung ist es unnötig kompliziert `liste_alle_zahlen` zu erstellen, wenn man sowieso nur die erste braucht. Da würde ein `re.search()` reichen. Und den aufgespaltenen `text` bräuchte man dann auch nicht mehr, denn so ein Match-Objekt weiss ja auch an welchem Index es auf den `text` passt.
Was soll das mit ',' und '.'? Hast Du mal ausprobiert was passiert wenn so ein Treffer vor einem ohne im `text` vorkommt?

Ausserdem wäre es vielleicht wünschenswert wenn der Code auch mit dem Fall sinnvoll umgehen könnte das *keine* Ziffernfolge im `text` vorkommt.

Wenn Du das in eine Funktion verpackst, wäre es zudem einfacher den Ansatz mal mit mehr als einem Testfall auszuprobieren.
Hey,

ich bekomme das leider so nicht hin wie du das meinst, könntest du mir das vielleicht zeigen wenn du Zeit dazu hast?



Bekomme bis jetzt nur das hin:

Code: Alles auswählen

import re

input = "text mit zahl 1 und auch ne 12 und ne 14"

def replace(match):
    new_number = int(match) + 1
    return str(new_number)

first_number = re.search('\d+', input).group()
new_string = re.sub(first_number, replace(first_number), input)
print(new_string)
input: "text mit zahl 1 und auch ne 12 und ne 14"
output: "text mit zahl 2 und auch ne 22 und ne 24"


input: "text mit zahl 12 und auch ne 13 und ne 14""
output: "text mit zahl 13 und auch ne 13 und ne 14"

habe es doch hin bekommen (glaube ich):

Code: Alles auswählen

import re

input = "text mit zahl 1556 und auch ne 1556 und ne 14"

def replace(match):
    new_number = int(match) + 1
    return str(new_number)

first_number = re.search('\d+', input).group()
new_string = re.sub(first_number, replace(first_number), input, count=1)
print(new_string)
input: "text mit zahl 1556 und auch ne 1556 und ne 14"
output: "text mit zahl 1557 und auch ne 1556 und ne 14"
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

@Jankie: Raten ist nicht Programmieren. Du missbrauchst re.sub als einfaches str.replace, mit den negativen Nebenwirkungen, dass reguläre Ausdrücke manche Zeichen anders behandeln, was Du ignorierst.

Vielleicht hilft Dir ja das zu verstehen, was Du falsch machst:

Code: Alles auswählen

def add_one(match):
    return str(int(match.group(0)) + 1)
new_string = re.sub('\d+', add_one, input, count=1)
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

Also ruft re.sub die als Parameter übergebene Funktion schon mit dem Match auf ohne dass ich das explizit übergeben muss? Und meine Zeile

Code: Alles auswählen

first_number = re.search('\d+', string).group()
wird ja dann unnötig weil das Match erst in der Funktion gegroupt wird?

Code: Alles auswählen

import re

def replace(match):
    return str(int(match.group(0)) + 1)
   
def increase_first_number_of_string(string):
    try:
        new_string = re.sub('\d+', replace, string, count=1)
        return new_string
    except(AttributeError):
        print("Keine Zahl im String")
        
string = input("String eingeben, bei dem die erste Zahl um 1 erhoeht werden soll: ")
new_string = increase_first_number_of_string(string)

print(new_string)
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

@Jankie: wenn Du in Deine vorherige "Lösung" den Aufruf von re.sub genau anschaust, wirst Du merken, dass da gar kein Regulärer Ausdruck verwendet wird.
Und Du fängst schon wieder mit Raten an. An welcher Stelle meinst Du denn, dass ein AttributeError auftritt?

Die Klammern bei except sind überflüssig, und die "Fehlerbehandlung" sowieso Quatsch. Ein Fehler sollte nur dann und so behandelt werden, dass das Programm normal weiterlaufen kann. Bei Dir wäre das bei diesem Exceptionhandler nicht der Fall, weil die Funktion keinen String mehr zurückliefert sondern None, was dann später zu Problemen führen kann, und Du den eigentlichen Ursprung des Fehlers gar nicht mehr herausfinden kannst.
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

Sirius3 hat geschrieben: Montag 8. April 2019, 09:22 @Jankie: wenn Du in Deine vorherige "Lösung" den Aufruf von re.sub genau anschaust, wirst Du merken, dass da gar kein Regulärer Ausdruck verwendet wird.
Weiß nicht genau was du damit meinst..

Und ja das AttributeError tritt nirgends auf, hatte das noch drin als ich mit re.search die erste Zahl gesucht habe.

Code: Alles auswählen

import re

def replace(match):
    return str(int(match.group(0)) + 1)
   
def increase_first_number_of_string(string):
        new_string = re.sub('\d+', replace, string, count=1)
        return new_string
        
string = input("String eingeben, bei dem die erste Zahl um 1 erhoeht werden soll: ")
new_string = increase_first_number_of_string(string)

print(new_string)
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

Hast Du Dir die Parameter, die Du re.sub übergibst, angeschaut?
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

result = re.sub(pattern, repl, string, count=0, flags=0)

pattern: der reguläre Ausdruck, der abgeglichen werden soll
repl: ersetzt alle (außer es ist ein max angegeben) Vorkommen in der Zeichenkette durch repl. Gibt eine modifizierte Zeichenkette zurück. Statt einem String kann hier auch eine Funktion übergeben werden.
string: die Zeichenkette, die nach dem pattern durchsucht wird.
count: maximale Anzahl der zu ersetzenden Vorkommen
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

Und was hast Du in Deiner Version konkret für diese Parameter an Werten übergeben?
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

Code: Alles auswählen

re.sub('\d+', replace, string, count=1)
\d+ : Alle Zahlen von 0-9, die ein- oder mehr als einstellig sind
replace: die Funktion welche um 1 hoch zählt und dessen Ergebnis die erste Zahl ersetzen soll
string: der zu überprüfende Text
count = 1: da ich nur die erste Zahl ersetzen will
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

@Jankie: ich hatte nach Deiner Version gefragt, nicht meiner.
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

Code: Alles auswählen

first_number = re.search('\d+', input).group()
re.sub(first_number, replace(first_number), input, count=1)
first_number: die erste Zahl die er findet, die ein- oder mehr als einstellig sind (als string)
replace(first_number): eine Methode mit dem Parameter first_number (diese Methode erhöht die first_number um +1 und gibt diesen Wert zurück)
input: Der Text indem gesucht und ersetzt werden soll
count = 1, da ich nur die erste Zahl ersetzen will
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

Das heißt also, wenn Du die Werte deines Beispielstrings einsetzt:

Code: Alles auswählen

input = "text mit zahl 1556 und auch ne 1556 und ne 14"
new_string = re.sub("1556", "1557", input, count=1)
was nichts anderes ist als ein `str.replace`:

Code: Alles auswählen

new_string = input.replace("1556", "1557", 1)
Antworten