2012-04-13 3 views
2

Erhöhen ich diesen Code bekam:Manipulation Seltsamkeit String, wenn Hinter einstelligen

myString = 'blabla123_01_version6688_01_01Long_stringWithNumbers' 
versionSplit = re.findall(r'-?\d+|[[email protected]#$%^&*()_+.,<>{}]+|\W+?', myString) 

for i in reversed(versionSplit): 
    id = versionSplit.index(i) 
    if i.isdigit(): 
     digit = '%0'+str(len(i))+'d' 
     i = int(i) + 1 
     i = digit % i 
     versionSplit[id]=str(i) 
     break 

final = '' 
myString = final.join(versionSplit) 
print myString 

, die nur die letzte Ziffer von der Saite gegeben erhöhen annehmen. Aber wenn Sie diesen Code ausführen, werden Sie sehen, dass, wenn dieselbe Zeichenfolge in der Zeichenfolge wie die letzte vorhanden ist, diese nach und nach erhöht wird, wenn Sie das Skript weiterhin ausführen. Kann mir jemand helfen, herauszufinden, warum?

Vielen Dank im Voraus für jede Hilfe

+1

'id' ist ein Python-Wort reserviert, es für etwas anderes ändern – heltonbiker

+0

Die Linie' id = versionSplit.index (die übrigens auf Ihre Frage nicht in engem Zusammenhang steht) (i) 'findet das erste Vorkommen, nicht das letzte, wie Sie beabsichtigen –

Antwort

2

Die Frage der Verwendung der auf der Leitung list.index() Funktion ist 5. Dieser den Index der in einer Liste Auftreten eines Wertes zuerst zurückkehrt, von links nach rechts, aber der Code iteriert über die umgekehrte Liste (von rechts nach links). Es gibt viele Möglichkeiten, dies auszugleichen, aber hier ist einer, der die wenigsten Änderungen an Ihrem bestehenden Code vornimmt: Rückwärts über Indizes springen (vermeidet das Umkehren der Liste).

for idx in range(len(versionSplit)-1, -1, -1): 
    i = versionSplit[idx] 
    if chunk.isdigit(): 
     digit = '%0'+str(len(i))+'d' 
     i = int(i) + 1 
     i = digit % i 
     versionSplit[idx]=str(i) 
     break 
+1

' für idx umgekehrt (Bereich (len (versionSplit))): ' – dbr

+0

Ich danke Ihnen sehr für diese tolle Erklärung – cloud68

8

Gibt es einen Grund, warum man nicht etwas tun, wie folgt statt:

prefix, version = re.match(r"(.*[^\d]+)([\d]+)$", myString).groups() 
newstring = prefix + str(int(version)+1).rjust(len(version), '0') 

Hinweise:

  • Dies wird tatsächlich "carry over" die Versionsnummern richtig: ("09" -> "10") und ("99" -> "100")
  • Diese Regex setzt mindestens ein nicht-numerisches Zeichen voraus, bevor die letzte Version Teilkette am Ende. Wenn dies nicht übereinstimmt, wird ein AttributeError geworfen. Sie könnten es umstrukturieren, um eine geeignetere oder spezifischere Ausnahme auszugeben (z. B. wenn re.match(...)None zurückgibt; weitere Informationen finden Sie in den Kommentaren unten).

Entsprechend anpassen.

+0

Nicht getestet, aber ich vermute das wird nicht hilfreiche Dinge tun, wenn die Zeichenfolge nicht in einer Ziffer endet? – dbr

+1

Das ist die typische Lösung, die über das hinausgeht, was beantwortet wird. Ich mag das. +1 – heltonbiker

+0

@dbr Die Liste soll * angeblich * in einer Ziffer enden. Eine Ausnahme oder ein Fehler müsste geworfen werden, wenn nicht, denke ich. – heltonbiker

1
myString = 'blabla123_01_version6688_01_01veryLong_stringWithNumbers01' 
versionSplit = re.findall(r'-?\d+|[^\-\d]+', myString) 

for i in xrange(len(versionSplit) - 1, -1, -1): 
    s = versionSplit[i] 
    if s.isdigit(): 
     n = int(s) + 1 
     versionSplit[i] = "%0*d" % (len(s), n) 
     break 

myString = ''.join(versionSplit) 
print myString 

Hinweise:

  • Es ist albern die .index() Methode zu verwenden, um zu versuchen, die Zeichenfolge zu finden. Verwenden Sie einfach einen dekrementierenden Index, um jeden Teil von versionSplit auszuprobieren. Dies war, wo Ihr Problem war, wie oben von @ David Robinson kommentiert.

  • Verwenden Sie nicht id als Variablenname; Sie verdecken die eingebaute Funktion id().

  • Dieser Code verwendet die * in einer Formatvorlage, die eine Ganzzahl akzeptiert und die Breite festlegen.

  • Ich habe das Muster vereinfacht: Entweder stimmen Sie mit einer Ziffer überein (mit optionalem führenden Minuszeichen) oder Sie stimmen mit Nicht-Ziffern überein.

  • Ich habe das getestet und es scheint zu funktionieren.

+0

Ich danke Ihnen sehr für diese tolle Erklärung – cloud68

1

Zuerst drei Noten:

  1. id ist ein reservierter Python Wort;
  2. Zum Verbinden, eine pythonic Idiom ist ''.join(), eine wörtliche leere Zeichenkette mit
  3. reversed() einen Iterator zurückgibt, keine Liste. Deshalb verwende ich list(reversed()), um später rev.index(i) zu tun.

Corrected Code:

import re 

myString = 'blabla123_01_version6688_01_01veryLong_stringWithNumbers01' 
print myString 
versionSplit = re.findall(r'-?\d+|[[email protected]#$%^&*()_+.,<>{}]+|\W+?', myString) 

rev = list(reversed(versionSplit)) # create a reversed list to work with from now on 

for i in rev: 
    idd = rev.index(i) 
    if i.isdigit(): 
     digit = '%0'+str(len(i))+'d' 
     i = int(i) + 1 
     i = digit % i 
     rev[idd]=str(i) 
     break 

myString = ''.join(reversed(rev)) # reverse again only just before joining 
print myString