Zahlen 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.
python
User
Beiträge: 15
Registriert: Dienstag 14. Januar 2003, 07:20

Hallo,

ich möchte eine Zahl, sagen wir 12000, so formatieren, dass 12.000,00 herauskommt. Wie mach ich das? In PHP gibt's dafür ja number_format, gibts sowas auch für Python?
python

[url=http://www.python-welt.de/][img]http://www.python-welt.de/bilder/banner/banner_100x20.gif[/img][/url]
RicmanX
User
Beiträge: 69
Registriert: Donnerstag 29. August 2002, 17:10
Wohnort: Erfurt
Kontaktdaten:

print "%0.2f" % float(12000)
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Hallo!

Keine Ahnung, ob's für Python sowas gibt. Das Folgende bildet wohl in etwa die PHP-Funktion nach.

Code: Alles auswählen

import re

def number_format(zahl):
   zahl = "%.2f" % zahl
   zahl = zahl.replace(".",",")
   nochmal = 1 
   while nochmal:    
      (zahl,nochmal) = re.subn(r"(\d)(\d\d\d\D)",r"\1.\2",zahl)
   return zahl

print number_format(12431554323.44)
Ausgabe: 12.431.554.323,44

HTH
Jan
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

hier mal ohne RE. Ich glaube aber nicht, dass man damit schneller läuft, war nur mal ne kleine Bastelei für Pythonversionen, die noch kein RE in der neuen Art unterstützen (Bsp Python 1.4 oder 1.5):

Code: Alles auswählen

def split(s, size): 
    return map(lambda i: s[i:i+size], xrange(0,len(s),size))
def reverse(s):
    l=map(None,s)
    l.reverse()
    return ('').join(l)
def formatter(num):
    num=("%.2f"%num).replace('.',',')
    int_part=num[:num.find(',')]
    return reverse(('.').join(split(reverse(int_part),3)))+num[num.find(','):]
edit: ich habs neugierig wie ich bin doch mla auf Zeit getestet und ohne re isses sogar schneller (1/5 der Zeit). Allerdings sind beide Zeiten verschwindend gering, unterhalb von millisekunden und somit völlig egal. Eleganter find ich trotzdem Voges seine Variante. :wink:
Gast

Hi python,

Code: Alles auswählen

>>> import locale
>>> locale.setlocale(locale.LC_ALL, '')
'de_DE.ISO-8859-1'
>>> locale.format("%.2f",12000,1)
'12.000,00'
>>>
Gruß

Dookie
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

:idea: hmmm... das ist interessant, Dookie. Kann ich mit dem Modul local auch strings statt Zahlen formatieren? Wenn ja würde ich nämlich gerne eine ähnliche Darstellung, normiert für Deutschland, von dem String den time.asctime zurückgibt...
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hi milan,

im Modul locale gibt es ab pythonversion 2.2 die Funktion nl_langinfo() die verschiedene Formatstrings auch für strftime() aus dem modul time, zurückgibt.

Code: Alles auswählen

>>> import time
>>> time.strftime(locale.nl_langinfo(locale.D_T_FMT))
'Die 25 Feb 2003 20:00:07 CET'
>>>
Gruß

Dookie
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

aber irgendwie nur unter unix/linux. ich habs bei mir unter win versucht und die gibt es nicht (hab 2.2.2). dann hab ich nen ssh auf nen unixserver gemacht und da geht es... :?
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

python hat geschrieben:ich möchte eine Zahl, sagen wir 12000, so formatieren, dass 12.000,00 herauskommt.
Genau das wollte ich nun auch tun, deswegen hab ich noch mal diesen alten Thread rausgekramt...
Hab ein wenig mit locals rumgespielt, aber keine Lösung gefunden.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Jens hat geschrieben:Genau das wollte ich nun auch tun, deswegen hab ich noch mal diesen alten Thread rausgekramt...
Hab ein wenig mit locals rumgespielt, aber keine Lösung gefunden.
Hi jens!

Hier ein Auszug aus einem meiner Programme:

Code: Alles auswählen

#----------------------------------------------------------------------
def format_currency(float_number):
   """
   Formatiert die uebergebene Zahl
   """

   import locale
   LC_NUMERIC = "german"
   CUR_FORMAT = "%0.2f"

   # Richtige Verwendung von LC_NUMERIC setzen
   old_lc_numeric = locale.setlocale(locale.LC_NUMERIC)
   locale.setlocale(locale.LC_NUMERIC, LC_NUMERIC)
   
   retval = locale.format(CUR_FORMAT, float(float_number))

   # Wieder auf das alte LC_NUMERIC umschalten
   locale.setlocale(locale.LC_NUMERIC, old_lc_numeric)

   return retval
lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ist schon ziemlich kompliziert, für eine einfache Aufgabe :?

Es klappt leider bei mir nicht:
/usr/lib/python2.4/locale.py in setlocale(category=1, locale='german')
379 # convert to string
380 locale = normalize(_build_localename(locale))
381 return _setlocale(category, locale)
382
383 def resetlocale(category=LC_ALL):
global _setlocale = <built-in function setlocale>, category = 1, locale = 'german'

Error: unsupported locale setting
args = ('unsupported locale setting',)
Könnte allerdings auch an meinen locales Einstellungen, meines Linux Servers liegen?!?!

EDIT: Jep, auf Hosteurope geht's: http://www.jensdiemer.de/Programmieren/
Allerdings gibt's da keine Tausender Punkte :(

Also stimmt was auf meinem Lokalen Server nicht :(

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Aha, so mach ich's jetzt:

Code: Alles auswählen

        file_KBytes = item_stat[stat.ST_SIZE]/1024.0
        try:
            locale.setlocale(locale.LC_ALL, "de_DE.UTF-8")
            print "%s KB" % locale.format("%0.1f", file_KBytes, True)
        except:
            print "%0.1f KB" % file_KBytes
Mit "de_DE.UTF-8" geht's bei mir lokal und bei Hosteurope...

Hab noch das http://starship.python.net/pipermail/py ... .html#6011 gefunden...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

jens hat geschrieben:Ist schon ziemlich kompliziert, für eine einfache Aufgabe :?
[...]
Error: unsupported locale setting
args = ('unsupported locale setting',)
Könnte allerdings auch an meinen locales Einstellungen, meines Linux Servers liegen?!?!
Hi Jens!

Ich habe übersehen, dass dieses Programm, von dem ich den Codeausschnitt zitiert habe, unter Windows läuft. Leider kannst du unter Linux keinesfalls davon ausgehen, dass jeder die gleichen bzw. alle Locales zur Verfügung hat. Das kommt darauf an, welche Locales beim Kompilieren in die glibc übersetzt wurden.

Am besten, du verwendest den Tipp im Beitrag von Voges oder Milan. Der funktioniert immer -- sowohl unter Windows -- als auch unter Linux.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
HarryH
User
Beiträge: 266
Registriert: Freitag 23. Mai 2003, 09:08
Wohnort: Deutschland

Hallo zusammen,

Habe auch noch etwas herumprobiert.
Bin auf folgende Lösung gekommen:

Code: Alles auswählen


import re

def formatter(number, format = "%.2f", dezChar = ",", groupChar = ".", groupRange = 3):
    regex = re.compile("^\d*\D?\d{1,%s}|\d{1,%s}" % (groupRange, groupRange))
    form_num = groupChar.join(regex.findall((format % number).replace(".", dezChar)[::-1]))[::-1]
    return form_num

number = 1234567890.789
print formatter(number, "%.2f")
Funktioniert in etwa doppelt so schnell wie über das 'locale'-Modul!
Schreibt man die Funktion noch etwas um und übergibt die regex direkt,
so ist nochmals ein Geschwindigkeitssteigerung um ca. 30% möglich.

Vielleicht weiß ja jemand noch eine Verbesserung dazu!?
Gruß, Harry
cime
User
Beiträge: 152
Registriert: Dienstag 24. Mai 2005, 15:49

darf ich ma fragen warum das hier so kompliziert gemacht wird?

er will doch nur eine einfache formatierung, die man auch selber schreiben kann, ohne irgendwelche module, oder hab ich das falsch verstanden?

Code: Alles auswählen

#format_number.py

def format_number(number):
    hinter_komma=str(number%1)[2:]
    if not hinter_komma:
        hinter_komma="00"
    elif len(hinter_komma)==1:
        hinter_komma+="0"
    else:
        hinter_komma=hinter_komma[0:2]
    string=","+hinter_komma
    number=int(number)
    x=1
    while 1000**x<=number:
        string="."+str(number%(1000**x))[0:3]+string
        x+=1
    string=str(number/(1000**(x-1)))+string
    return string

print format_number(input("Zahl: "))
das hier macht exakt das, was er haben will, oder?
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ich muß sagen, ich bin etwas enttäuscht... Warum geht's nicht einfach mit einem passendem String-Formatter???

Ich denke es kommt doch häufiger vor, das jemand tausenderpunkte für große Zahlen haben will.

Ist doch nicht's ausßergewäöhnliches...

Wäre es also ein Feature Request?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

@HarryH: Deine Lösung ist schon nicht schlecht. Sie funktioniert allerdings nicht richtig, wenn "%i" als Format benutzt wird :(

Bei mit kommt allerdings beides vor... Deshalb meine Variante:

Code: Alles auswählen

def formatter( number, format = "%.2f" ):
    """Formatiert Zahlen mit Tausenderpunkte"""
    num_string = format % number # Formatierung anwenden
    try:
        pre, post = num_string.split(".")
    except ValueError: # Ganzzahl liegt vor
        pre  = num_string
        post = False
    pre = pre[::-1] # umkehren
    no_split = re.findall( r"\d{3,3}|\d{0,2}", pre )[:-1] # Aufsplitten
    no = ".".join( no_split )[::-1] # Tausenderpunkte + umkehren
    if post: no += ",%s" % post # Nachkommastellen anfügen
    return no

print formatter( 1234567.89 )
print formatter( 12345.1,"%f" )
print formatter( 1234.0,"%i" )
1.234.567,89
12.345,100000
1.234
EDIT: Kann es sein, das eine Stringumkehrung mit [::-1] nicht mit älteren Python Versionen funktioniert :(

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

jens hat geschrieben:EDIT: Kann es sein, das eine Stringumkehrung mit [::-1] nicht mit älteren Python Versionen funktioniert :(
Sie dir mal NeuereVersionen an, dort steht das unter "Slice Syntax".
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Leonidas hat geschrieben:Sie dir mal NeuereVersionen an, dort steht das unter "Slice Syntax".
Also gibt's das erst seid Python v2.4 :( Schade... Nunja, hier eine Version, dich auch mit >2.4 läuft:

Code: Alles auswählen

def formatter( number, format = "%.2f" ):
    """Formatiert Zahlen mit Tausenderpunkte"""
    def reverse( string ):
        # ersatz für string[::-1] welches erst ab v2.4 gibt :(
        l = re.findall(".",string)
        l.reverse()
        return "".join( l )

    num_string = format % number # Formatierung anwenden
    try:
        pre, post = num_string.split(".")
    except ValueError: # Ganzzahl liegt vor
        pre  = num_string
        post = False

    pre = reverse( pre ) # umkehren
    num_split = re.findall( r"\d{3,3}|\d{0,2}", pre )[:-1] # Aufsplitten
    num = ".".join( num_split ) # Tausenderpunkte + umkehren
    num = reverse( num )
    if post: num += ",%s" % post # Nachkommastellen anfügen
    return num

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
HarryH
User
Beiträge: 266
Registriert: Freitag 23. Mai 2003, 09:08
Wohnort: Deutschland

Hi,

Code: Alles auswählen

def __formatter(number, format = "%.2f", decChar = ",", groupChar = ".", groupRange = 3):
    """
    Convert to required format
    number =      number to convert
    format =      python string formatting (%)
    decChar =     decimal char for the converted format
    groupChar =   group char for the converted format
    groupRange =  group range for the converted format

    For example:
    __formatter(1234567890.987, "%.2f", ",", ".", 3)
    ==> 1.234.567.890,99

    """

    regex = re.compile("^ *\d*\D\d{1,%s}|\d{1,%s} *" % (groupRange, groupRange))
    form_num = groupChar.join(regex.findall((format % number).replace(".", decChar)[::-1]))[::-1]
    return form_num


Funktioniert nun auch für int-Zahlen.
Außerdem werden auch vorn oder hinten angestellte Leerzeichen mit ausgegeben (z.b. beim Format "%20.2f")

Nun noch eine Frage:
Gibt es bei regex eine Möglichkeit den String von hinten nach vorne zu durchsuchen? :?:
Dann könnte man sich das zweimalige Umkehren des Strings sparen.
Gruß, Harry
Antworten