4

I am searching for the proper way of German number formatting (e.g. 1.000,1234) in Python under Windows OS.

I tried locale.setlocale but did not succeed.

Instead, I have written a function to come up with the desired output.

Is there a better way?

def ger_num(number, precision=3):
    """
    returns german formatted number as string or an empty string
    """
    if number is not None:
        try:
            my_number = "{:,f}".format(number)
        except ValueError:
            return ""

        decimals, fraction = my_number.split(".")[0], my_number.split(".")[1]
        decimals = decimals.replace(",", ".")

        if precision:
            return decimals + "," + fraction[:precision]
        else:
            return decimals

    else:
        return ""
blhsing
  • 91,368
  • 6
  • 71
  • 106
Fab
  • 213
  • 3
  • 15
  • please provide a clear description of your inputs and outputs. – SuperKogito Apr 10 '19 at 15:58
  • What exactly have you tried with `locale`? Perhaps your platform doesn't support it? See the many answers here: https://stackoverflow.com/questions/14287051/german-number-separators-using-format-language-on-osx – juanpa.arrivillaga Apr 10 '19 at 16:01

4 Answers4

5

You can use locale.setlocale to set the locale to de and then use locale.format to format your number:

import locale
locale.setlocale(locale.LC_ALL, 'de')
print(locale.format('%.4f', 1000.1234, 1))

This outputs:

1.000,1234
blhsing
  • 91,368
  • 6
  • 71
  • 106
  • 1
    On Debian you might want to check your specific locale identifiers by running `locale -a` and if it's missing check out `man locale-gen`. I'm using `de_DE.utf8`. Also, `locale.format` is deprecated in Python 3.7. Use `locale.format_string()` instead. – felixhummel Sep 30 '19 at 14:26
4

If for some reason locale does not work for you (or is not desired), then the easiest other option would probably be to use string replacement, like suggested in this already mentioned answer (which draws its answer from the PEP-378).

You can always encapsulate that in a function, maybe like this:

def format_number(number, precision=3):
    # build format string
    format_str = '{{:,.{}f}}'.format(precision)

    # make number string
    number_str = format_str.format(number)

    # replace chars
    return number_str.replace(',', 'X').replace('.', ',').replace('X', '.')

This works well for int, float and Decimal:

>>> format_number(1)
'1,000'
>>> format_number(1, 2)
'1,00'
>>> format_number(1, 7)
'1,0000000'
>>> format_number(1234567, 7)
'1.234.567,0000000'

>>> format_number(1234567.9988, 7)
'1.234.567,9988000'
>>> format_number(1234567.9988, 2)
'1.234.568,00'

>>> from decimal import Decimal
>>> format_number(Decimal('1234567.9988'), 2)
'1.234.568,00'
>>> format_number(Decimal('1234567.9988'), 5)
'1.234.567,99880'
>>> format_number(Decimal('1234567.9988'), 0)
'1.234.568'
>>> format_number(Decimal('123456'), 5)
'123.456,00000'
Ralf
  • 16,086
  • 4
  • 44
  • 68
  • I was able to edit this func into something that allowed me to display euro symbol in front of euro formatted currency - much neater than worrying about locale – RozzA Oct 01 '20 at 06:35
0

Thanks for the help. If anyone finds this useful I do provide the code for my final solution here.

ger_num.py:

def ger_num(number, digits=2):
    '''
    retruns <number> as german formattet string (thousands-.),
    rounds to n <digits>.

    <number> == None OR (!= INT AND != FLOAT) returns '' (empty STR)
    '''
    import locale
    locale.setlocale(locale.LC_ALL, 'de')
    if number is None:
        return ''
    if not isinstance(number, int) and not isinstance(number, float):
        return ''
    else:
        format = '%.'+str(digits)+'f'
        return locale.format_string(format, number, 1)


if __name__ == "__main__":
    pass
Fab
  • 213
  • 3
  • 15
0

If locale has an for you issue again, I would propose simple string replacement. The proposed format_number function above is great, but it does not always preserve the input. For instance, format_number(Decimal('1234567.9988'), 0) does transform English to German format, but it removes the numbers after the decimal point. A simple safe way to just tranform any English string number to a German string number is this:

de_number = number.replace(".", "$DECIMAL$")
de_number = de_number.replace(",", ".")
de_number = de_number.replace("$DECIMAL$", ",")

From the post I gathered that the input number is always positive, but in case it can be negative, you could use number[1:]instead of number. If the majority of the input numbers are negative, it might worth using locale, which seems to deal with them by default.

To format an input German string number into an English string number without altering the input again, use:

en_number = number.replace(",", "$DECIMAL$")
en_number = en_number.replace(".", ",")
en_number = en_number.replace("$DECIMAL$", ".")

If en_number does not have thousand separators but only decimal points, it can now be properly used in Python like in float(en_number). For instance, float("5000.0") works, but the German equivalent float("5000,0") would give a ValueError.

KLaz
  • 446
  • 3
  • 11