def editmoney(n) :
return((",".join(reduce(lambda lst, item : (lst + [item]) if
item else lst,
re.split(r'(\d\d\d)',str(n)[::-1]),[])))[::-1])
>>> editmoney(0)
'0'
>>> editmoney(13535)
'13,535'
>>> editmoney(-14535)
'-14,535'
>>> editmoney(123456)
'123,456'
>>> editmoney(1234567890)
'1,234,567,890'
>>> editmoney(-1234)
'-1,234'
The basic idea here is that we want to split the string of digits
into groups of 3 digits, aligned at the right. Because regular
expressions are right to left, we have to reverse the string to
do that, then reverse again at the end. s[::-1} reverses an
interable.
"split" with a capturing group introduces empty strings into the
list. Hence the "reduce" and lambda to get rid of them.
Any better ideas?
(Yes, I know there's a built-in feature for this scheduled for
Python 2.7.)
John Nagle
Too obscure. I usually use something like this:
def editmoney(n):
if n < 0: return '-' + editmoney(-n)
if n >= 1000:
return editmoney(n // 1000) + ',%03d'% (n % 1000)
return '%d'% n
> There's got to be a better way to do this:
>
>
> def editmoney(n) :
> return((",".join(reduce(lambda lst, item : (lst + [item]) if
> item else lst,
> re.split(r'(\d\d\d)',str(n)[::-1]),[])))[::-1])
What does the name "editmoney" mean?
Why the obfuscated one-liner? It's not like you're using it in-line,
you're putting it in a function, so who cares if it's one line or twenty?
def group_digits(n, size=3, sep=','):
"""Group int n in groups of size digits separated by sep."""
s = str(n)
m = len(s) % size
head = s[0:m]
tail = s[m:]
groups = [tail[i*size:(i+1)*size] for i in range(len(tail)//size)]
tail = sep.join(groups)
if head and tail:
return head + sep + tail
elif tail:
return tail
else:
return head
>>> group_digits(0)
'0'
>>> group_digits(1234567890)
'1,234,567,890'
>>> group_digits(1234567890, 4, ';')
'12;3456;7890'
Additional error checking, a better docstring, and extending it to
support negative numbers is left as an exercise.
--
Steven
>>> locale.setlocale(locale.LC_ALL, ("en_US", "UTF-8"))
'en_US.UTF8'
>>> print locale.currency(13535, grouping=True)
$13,535.00
>>> print locale.format("%d", 13535, grouping=True)
13,535
>>> locale.setlocale(locale.LC_ALL, "")
'de_DE.UTF-8'
>>> print locale.currency(13535, grouping=True)
13.535,00 €
>>> print locale.format("%d", 13535, grouping=True)
13.535
Peter
I had literally no idea this existed. Thanks.
Geremy Condra
>>>>> locale.setlocale(locale.LC_ALL, "")
>> 'de_DE.UTF-8'
>>>>> print locale.currency(13535, grouping=True)
>> 13.535,00 €
>>>>> print locale.format("%d", 13535, grouping=True)
>> 13.535
>>
>> Peter
>
> I had literally no idea this existed. Thanks.
I knew it existed, but completely forgot about it.
Thanks also Peter.
--
Steven
Okay, so if I'm writing a wsgi app, and I want to format depending on
the choices of the currently logged in users, what would you recommend?
I can't do setlocale, since that would affect all users, and in a
mult-threaded environment that would be bad.
Does that mean the whole locale package is useless to all web-app builders?
Chris
from re import *
class editmoney(float):
def __init__(self,mymoney):
self.mymoney = mymoney
def __str__(self):
temp = "%.2f" % self.mymoney
profile = compile(r"(\d)(\d\d\d[.,])")
while 1:
temp, count = subn(profile,r"\1,\2",temp)
if not count: break
return temp
Blame it on the C guys ;)
I've seen
http://babel.edgewall.org/wiki/Documentation/intro.html
http://babel.edgewall.org/wiki/ApiDocs/babel.numbers
http://babel.edgewall.org/wiki/BabelFaq#WhatalternativesexistforPythonprojects
mentioned here but not yet tried it myself.
Peter
Here's a more elegant variant, using regexp lookahead:
def thous_format(integer_string):
"""
add comma thousands separator(s) to an integer-valued string
"""
return re.sub(r'(\d{3})(?=\d)', r'\1,', integer_string[::-1])[::-1]
I *thought* that I had found this on python-list on or about July 5, but
I didn't find the thread after a search through the archives.
-John
def thous_format(integer_string):
"""
add comma thousands separator(s) to an integer-valued string
"""
return re.sub(r"(?<=\d)(?=(?:\d\d\d)+$)", ",", integer_string)
> You don't need to reverse the string:
>
> def thous_format(integer_string):
> """
> add comma thousands separator(s) to an integer-valued string
> """
> return re.sub(r"(?<=\d)(?=(?:\d\d\d)+$)", ",", integer_string)
Nice! My first encounter with a look-behind! It appears that a slight
simplification is possible:
return re.sub(r"(?<=\d)(?=(\d\d\d)+$)", ",", integer_string)
There no harm in putting \d\d\d into a group, though the group is never
used.
-John
> You don't need to reverse the string:
>
> def thous_format(integer_string):
> """
> add comma thousands separator(s) to an integer-valued string
> """
> return re.sub(r"(?<=\d)(?=(?:\d\d\d)+$)", ",", integer_string)
Nice! My first encounter with a look-behind! It appears that a slight
You're welcome!
In [1]: '{:,}'.format(-12345678)
Out[1]: '-12,345,678'
What does this have to do with my question about locales in
multi-threaded environments?
Chris
--
Simplistix - Content Management, Batch Processing & Python Consulting
- http://www.simplistix.co.uk