Zahlen innerhalb eines String formatieren

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
finswimmer77
User
Beiträge: 13
Registriert: Freitag 14. Dezember 2012, 22:07

Hallo,
wie ich dafür sorgen kann, dass Zahlen mindestens 2 Stellen besitzen hab ich in zwischen rausbekommen:

Code: Alles auswählen

'%0.2d' %(3)
Nun hab ich hier aber z.B. folgenden String vorliegen

Code: Alles auswählen

a='E3b'
Wie kann ich daraus ein 'E03b' machen?

(Der String und die Zahlen sind natürlich variabel. Und exakter hab ich nicht einen String sondern eine Liste mit mehreren)

Vielen Dank schon mal für Unterstützung.

finswimmer
Zuletzt geändert von finswimmer77 am Montag 17. Dezember 2012, 09:24, insgesamt 1-mal geändert.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

finswimmer hat geschrieben:Der String und die Zahlen sind natürlich variabel.
Was meinst Du mit "variabel"? Das ist ja zur Beantwortung nicht unerheblich... :)
Ich denke, Du wirst am re-Modul nicht vorbeikommen.

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
pixewakb
User
Beiträge: 1411
Registriert: Sonntag 24. April 2011, 19:43

Wie entstehen diese Strings? Kommen die aus einer Datei (fertig) oder setzt du die erst in einem Programm zusammen???
finswimmer77
User
Beiträge: 13
Registriert: Freitag 14. Dezember 2012, 22:07

Hallo,
also ich lese Datein bzw. Ordner-Namen ein. Diese haben in etwa das Format "ABC E1", es sind aber auch welche dabei die z.B. so aussehen "ABC E01_F" und so weiter.

Unterm Strich bleibt, ich habe Strings in denen Zahlen auftauchen, manche mit führender 0 wenn sie kleiner 10 sind und manche ohne. Ich möchte dass in diesen Strings alle Zahlen kleiner 10 eine führende 0 haben.

Ich hab schon befürchtet, dass ich da wohl nicht im Regular Expression drumherumkomme...

fin swimmer
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Wenn es ohne Regular Expressions sein soll, wäre das hier vielleicht ein Lösungsansatz. Geht möglicherweise auch eleganter.

Code: Alles auswählen

import string

def format_name(name):
    out = []
    prev_is_digit = False
    for character in name:
        if character in string.digits[1:] and not prev_is_digit and out:
            out.append('0')
        out.append(character)
        prev_is_digit = character in string.digits
    name = ''.join(out)
    try:
        if name[0] in string.digits and name[1] not in string.digits:
            name = "0%s" % name
    except IndexError:
        pass
    return name
    
if __name__ == '__main__':
    # simple test
    for s in ('E3b', 'E03b', 'E13b', 'ABC E1', 'ABC E01', '1ABC E012',
              '12ABC', '0123ABC'):
        print s, format_name(s)
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Mit regex:

Code: Alles auswählen

def wrap_zfill(s):
    if s.group(0):
        return s.group(0).zfill(2)

>>> re.sub('(\d*)', wrap_zfill, 'ABC E01_F')
'ABC E01_F'
>>> re.sub('(\d*)', wrap_zfill, 'ABC E1_F')
'ABC E01_F'
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@mutetella: Das ``if`` sollte man sich sparen können wenn man ein Muster angibt das keine leeren Treffer erzeugt: r'\d+'. (Die Klammern sind auch nicht nötig.)
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@BlackJack
Weißt Du eigentlich, wie lange ich 'rumprobiert habe, bis ich mir nicht mehr anderst zu helfen wusste, als dieses 'if' einzubauen...? :oops:

Es ist zum Verzweifeln!

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Oder so:

Code: Alles auswählen

def format_name(name):
    return re.sub(r'\d+', lambda x: x.group(0).zfill(2), name)
(BlackJack war mal wieder schneller)
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

oder so:

Code: Alles auswählen

def format_name(name):
    return re.sub(r'(?<!\d)(?=\d(\D|$))','0',name)
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@Sirius3
Könntest Du mir Deine Lösung mal bitte aufdröseln? Ich verstehe Deine regex so:

Code: Alles auswählen

voriges kein digit und nächstes ein digit auf das kein digit oder Ende folgt
Folglich stehe ich beim Beispiel 'p1next' auf dem 'n'. Wie kommt es, dass 'sub' vor die '1' (oder hinter dem 'p') ein '0' einfügt? Warum fügt 'sub' überhaupt etwas ein?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Sirius3: Schönes Beispiel für look-behind und non-consuming look-ahead (hatte ich zuvor aus dem Stegreif nicht parat). IMHO eignet sich das Problem auch prima als Übungsaufgabe unter Einsatz von regex sowie ohne. Werde ich mir merken.
finswimmer77
User
Beiträge: 13
Registriert: Freitag 14. Dezember 2012, 22:07

Hallo,
vielen Dank für eure zahlreichen Antworten!

Ich hab mich jetzt für diese Variante entschieden:

Code: Alles auswählen

def format_name(name):
    return re.sub(r'\d+', lambda x: x.group(0).zfill(2), name)
fin swimmer
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

mutetella hat geschrieben:@Sirius3
Könntest Du mir Deine Lösung mal bitte aufdröseln? Ich verstehe Deine regex so:

Code: Alles auswählen

voriges kein digit und nächstes ein digit auf das kein digit oder Ende folgt
Folglich stehe ich beim Beispiel 'p1next' auf dem 'n'. Wie kommt es, dass 'sub' vor die '1' (oder hinter dem 'p') ein '0' einfügt? Warum fügt 'sub' überhaupt etwas ein?

mutetella
@mutetella: Du hast den regulären Ausdruck schon richtig übersetzt. Er sucht die Position im String, an der
zuvor keine Ziffer steht und eine Ziffer und dann keine Ziffer folgt. Der eigentliche Suchtext ist aber leer.
Bei Deinem Beispiel stehst Du zwischen p und 1n und ersetzt das Nichts dazwichen durch eine 0 -> p01n.
Leider bedeutet \D 'ein Zeichen das keine Ziffer ist', so das ich sowohl auf keine Ziffer als auch auf Stringende
prüfen muss.
Antworten