[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.python

grouping in module 'locale'

Roman Bertle

1/25/2008 4:46:00 PM

Hello,

I try to format monetary values using the locale module, python2.5:

Python 2.5.2a0 (r251:54863, Jan 3 2008, 17:59:56)
[GCC 4.2.3 20071123 (prerelease) (Debian 4.2.2-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import locale
>>> locale.setlocale(locale.LC_ALL, 'de_AT.utf8')
'de_AT.utf8'
>>> locale.localeconv()
{'mon_decimal_point': ',', 'int_frac_digits': 2, 'p_sep_by_space': 1,
'frac_digits': 2, 'thousands_sep': '', 'n_sign_posn': 1,
'decimal_point': ',', 'int_curr_symbol': 'EUR ', 'n_cs_precedes': 1,
'p_sign_posn': 1, 'mon_thousands_sep': ' ', 'negative_sign': '-',
'currency_symbol': '\xe2\x82\xac', 'n_sep_by_space': 1,
'mon_grouping': [3, 3, 0], 'p_cs_precedes': 1, 'positive_sign': '',
'grouping': []}
>>> locale.currency(1234.5678, grouping=True, symbol=False)
'1234,57'

As you can see, the decimal point is correctly set to ','. But the
grouping is not done, every 3 digits should be separated by space (' ').
Using the 'de_DE.utf8' locale, ist works:

>>> locale.setlocale(locale.LC_ALL, 'de_DE.utf8')
'de_DE.utf8'
>>> locale.localeconv()
{'mon_decimal_point': ',', 'int_frac_digits': 2, 'p_sep_by_space': 1,
'frac_digits': 2, 'thousands_sep': '.', 'n_sign_posn': 1,
'decimal_point': ',', 'int_curr_symbol': 'EUR ', 'n_cs_precedes': 0,
'p_sign_posn': 1, 'mon_thousands_sep': '.', 'negative_sign': '-',
'currency_symbol': '\xe2\x82\xac', 'n_sep_by_space': 1, 'mon_grouping':
[3, 3, 0], 'p_cs_precedes': 0, 'positive_sign': '', 'grouping': [3, 3,
0]}
>>> locale.currency(1234.5678, grouping=True, symbol=False)
'1.234,57'

The difference here is that thounds_sep is '.', not ' '. If we look at the code
of locale.py, revision 55038, lines 157-161, the inserted spaces are later
deleted again:

while seps:
sp = formatted.find(' ')
if sp == -1: break
formatted = formatted[:sp] + formatted[sp+1:]
seps -= 1

This code is only called if numbers are formated as floating point, but not for
integers. The following works:

>>> locale.setlocale(locale.LC_ALL, 'de_AT.utf8')
'de_AT.utf8'
>>> locale.format('%d',1234.5678, grouping=True, monetary=True)
'1 234'

The reason for the space removal is explained in an earlier version of
locale.py, e.g. 42120:

# If the number was formatted for a specific width, then it
# might have been filled with spaces to the left or right. If
# so, kill as much spaces as there where separators.
# Leading zeroes as fillers are not yet dealt with, as it is
# not clear how they should interact with grouping.

But I don't know the why and how this code is necessary. Can anybody shed some
light on this issue?

Best Regards, Roman
1 Answer

Gabriel Genellina

1/26/2008 7:52:00 PM

0

En Fri, 25 Jan 2008 14:46:13 -0200, Roman Bertle <bertle@smoerz.org>
escribi�:

> I try to format monetary values using the locale module, python2.5:

>>>> locale.localeconv()
> {... 'mon_thousands_sep': ' '
>>>> locale.currency(1234.5678, grouping=True, symbol=False)
> '1234,57'
>
> As you can see, the decimal point is correctly set to ','. But the
> grouping is not done, every 3 digits should be separated by space (' ').

> Using the 'de_DE.utf8' locale, ist works:
>>>> locale.currency(1234.5678, grouping=True, symbol=False)
> '1.234,57'
>
> The difference here is that thounds_sep is '.', not ' '. If we look at
> the code
> of locale.py, revision 55038, lines 157-161, the inserted spaces are
> later
> deleted again:
>
> while seps:
> sp = formatted.find(' ')
> if sp == -1: break
> formatted = formatted[:sp] + formatted[sp+1:]
> seps -= 1

Looks like a bug, please report it at http://bugs....
Only *leading* and *trailing* spaces should be removed, the code above
removes spaces anywhere. This would be a better alternative:

if seps:
i = 0
while seps and i<len(formatted) and formatted[i]==' ':
seps -= 1
i += 1
formatted = formatted[i:]
if seps:
i = len(formatted)-1
while seps and i>=0 and formatted[i]==' ':
seps -= 1
i -= 1
formatted = formatted[:i+1]

Integers should be processed that way too:

py> locale.format('%10d', 1234567, True)
' 1.234.567'
(output has 12 characters, not 10)

Another issue: the code currently assumes that mon_thousands_sep and
thousands_sep are single characters, but they might be longer. There
should be a seps *= len(separator used) before the above whitespace
removal.

I'll try to make a patch tomorrow.

--
Gabriel Genellina