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
  • 77,832
  • 6
  • 59
  • 90
Fab
  • 193
  • 2
  • 14
  • 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

3 Answers3

4

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
  • 77,832
  • 6
  • 59
  • 90
  • 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
2

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
  • 14,947
  • 4
  • 39
  • 61
  • 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
  • 193
  • 2
  • 14