如何用逗号将数字打印成数千个分隔符?

时间:2021-10-22 21:40:50

I am trying to print an integer in Python 2.6.1 with commas as thousands separators. For example, I want to show the number 1234567 as 1,234,567. How would I go about doing this? I have seen many examples on Google, but I am looking for the simplest practical way.

我尝试在Python 2.6.1中打印一个整数,并使用逗号作为数千个分隔符。例如,我想显示1234567为1,234,567。我该怎么做呢?我在谷歌上看到过很多例子,但我在寻找最简单实用的方法。

It does not need to be locale-specific to decide between periods and commas. I would prefer something as simple as reasonably possible.

它不需要是特定于地区的,以在期间和逗号之间做出决定。我更喜欢尽可能简单的东西。

26 个解决方案

#1


1266  

For Python ≥ 2.7:

对于Python≥2.7:

"{:,}".format(value)

Per Format Specification Mini-Language,

每个迷你语言格式规范,

The ',' option signals the use of a comma for a thousands separator. For a locale aware separator, use the 'n' integer presentation type instead.

“,”选项表示在数千个分隔符中使用逗号。对于语言环境敏感的分隔符,请使用“n”整数表示类型。

#2


259  

I got this to work:

我让它工作:

>>> import locale
>>> locale.setlocale(locale.LC_ALL, 'en_US')
'en_US'
>>> locale.format("%d", 1255000, grouping=True)
'1,255,000'

Sure, you don't need internationalization support, but it's clear, concise, and uses a built-in library.

当然,您不需要国际化支持,但它是清晰、简洁的,并且使用了内置的库。

P.S. That "%d" is the usual %-style formatter. You can have only one formatter, but it can be whatever you need in terms of field width and precision settings.

“%d”是常见的%样式格式化程序。您只能有一个格式化程序,但它可以是任何您需要的字段宽度和精度设置。

P.P.S. If you can't get locale to work, I'd suggest a modified version of Mark's answer:

P.P.S.如果你不能让现场工作,我建议你修改一下马克的答案:

def intWithCommas(x):
    if type(x) not in [type(0), type(0L)]:
        raise TypeError("Parameter must be an integer.")
    if x < 0:
        return '-' + intWithCommas(-x)
    result = ''
    while x >= 1000:
        x, r = divmod(x, 1000)
        result = ",%03d%s" % (r, result)
    return "%d%s" % (x, result)

Recursion is useful for the negative case, but one recursion per comma seems a bit excessive to me.

递归对于负的情况很有用,但是每个逗号的递归似乎有点过分。

#3


89  

Here is the locale grouping code after removing irrelevant parts and cleaning it up a little:

这里是地区分组代码,删除不相关的部分,并清理它一点:

(The following only works for integers)

(以下仅适用于整数)

def group(number):
    s = '%d' % number
    groups = []
    while s and s[-1].isdigit():
        groups.append(s[-3:])
        s = s[:-3]
    return s + ','.join(reversed(groups))

>>> group(-23432432434.34)
'-23,432,432,434'

There are already some good answers in here. I just want to add this for future reference. In python 2.7 there is going to be a format specifier for thousands separator. According to python docs it works like this

这里已经有一些不错的答案了。我只是想补充一下,以备将来参考。在python 2.7中,将有一个用于数千个分隔符的格式说明符。根据python文档,它是这样工作的。

>>> '{:20,.2f}'.format(f)
'18,446,744,073,709,551,616.00'

In python3.1 you can do the same thing like this:

在python3.1中,你可以这样做:

>>> format(1234567, ',d')
'1,234,567'

#4


84  

For inefficiency and unreadability it's hard to beat:

对于低效率和不可读性来说,它很难被击败:

>>> import itertools
>>> s = '-1234567'
>>> ','.join(["%s%s%s" % (x[0], x[1] or '', x[2] or '') for x in itertools.izip_longest(s[::-1][::3], s[::-1][1::3], s[::-1][2::3])])[::-1].replace('-,','-')

#5


31  

Here's a one-line regex replacement:

这是一个单线regex替换:

re.sub("(\d)(?=(\d{3})+(?!\d))", r"\1,", "%d" % val)

Works only for inegral outputs:

只适用于不适当的输出:

import re
val = 1234567890
re.sub("(\d)(?=(\d{3})+(?!\d))", r"\1,", "%d" % val)
# Returns: '1,234,567,890'

val = 1234567890.1234567890
# Returns: '1,234,567,890'

Or for floats with less than 4 digits, change the format specifier to %.3f:

或者对于小于4位数的浮点数,将格式说明符更改为%.3f:

re.sub("(\d)(?=(\d{3})+(?!\d))", r"\1,", "%.3f" % val)
# Returns: '1,234,567,890.123'

NB: Doesn't work correctly with more than three decimal digits as it will attempt to group the decimal part:

NB:不能正确地使用超过3位小数,因为它将尝试将小数部分分组:

re.sub("(\d)(?=(\d{3})+(?!\d))", r"\1,", "%.5f" % val)
# Returns: '1,234,567,890.12,346'

How it works

Let's break it down:

让我们分解:

re.sub(pattern, repl, string)

pattern = \
    "(\d)           # Find one digit...
     (?=            # that is followed by...
         (\d{3})+   # one or more groups of three digits...
         (?!\d)     # which are not followed by any more digits.
     )",

repl = \
    r"\1,",         # Replace that one digit by itself, followed by a comma,
                    # and continue looking for more matches later in the string.
                    # (re.sub() replaces all matches it finds in the input)

string = \
    "%d" % val      # Format the string as a decimal to begin with

#6


15  

You can also use '{:n}'.format( value ) for a locale representation. I think this is the simpliest way for a locale solution.

您还可以使用“{:n}”。格式(值)用于区域设置表示。我认为这是语言环境解决方案最简单的方法。

For more information, search for thousands in Python DOC.

有关更多信息,请在Python文档中搜索数千条。

For currency, you can use locale.currency, setting the flag grouping:

对于货币,您可以使用区域设置。货币,设置国旗分组:

Code

代码

import locale

locale.setlocale( locale.LC_ALL, '' )
locale.currency( 1234567.89, grouping = True )

Output

输出

'Portuguese_Brazil.1252'
'R$ 1.234.567,89'

#7


14  

This is what I do for floats. Although, honestly, I'm not sure which versions it works for - I'm using 2.7:

这是我为浮点数所做的。虽然,老实说,我不确定它适用于哪个版本——我使用的是2.7:

my_number = 4385893.382939491

my_string = '{:0,.2f}'.format(my_number)

Returns: 4,385,893.38

返回:4385893 .38点

Update: I recently had an issue with this format (couldn't tell you the exact reason), but was able to fix it by dropping the 0:

更新:我最近遇到了这个格式的问题(不能告诉您确切的原因),但是可以通过删除0来修复它:

my_string = '{:,.2f}'.format(my_number)

#8


12  

I'm surprised that no one has mentioned that you can do this with f-strings in Python 3.6 as easy as this:

我很惊讶没有人提到你可以用Python 3.6中的f-string来做这个:

>>> num = 10000000
>>> print(f"{num:,d}")
10,000,000

... where the part after the colon is the format specifier. The comma is the separator character you want, so f"{num:_d}" uses underscores instead of a comma.

…在冒号后面的部分是格式说明符。逗号是您想要的分隔符,所以f“{num:_d}”使用下划线而不是逗号。

This is equivalent of using format(num, ",d") for older versions of python 3.

这相当于使用了旧版本的python 3的格式(num,“d”)。

#9


10  

I'm sure there must be a standard library function for this, but it was fun to try to write it myself using recursion so here's what I came up with:

我确信这里面一定有一个标准的库函数,但是尝试用递归来写它是很有趣的所以这就是我想到的:

def intToStringWithCommas(x):
    if type(x) is not int and type(x) is not long:
        raise TypeError("Not an integer!")
    if x < 0:
        return '-' + intToStringWithCommas(-x)
    elif x < 1000:
        return str(x)
    else:
        return intToStringWithCommas(x / 1000) + ',' + '%03d' % (x % 1000)

Having said that, if someone else does find a standard way to do it, you should use that instead.

话虽如此,如果别人确实找到了一种标准的方法,你应该用它来代替。

#10


8  

From the comments to activestate recipe 498181 I reworked this:

从评论到activestate recipe 498181,我重新做了这个:

import re
def thous(x, sep=',', dot='.'):
    num, _, frac = str(x).partition(dot)
    num = re.sub(r'(\d{3})(?=\d)', r'\1'+sep, num[::-1])[::-1]
    if frac:
        num += dot + frac
    return num

It uses the regular expressions feature: lookahead i.e. (?=\d) to make sure only groups of three digits that have a digit 'after' them get a comma. I say 'after' because the string is reverse at this point.

它使用正则表达式特性:lookahead (?=\d),以确保只有三个数字的组在得到一个逗号之后才有一个数字。我说" after "因为这个字符串在这里是反向的。

[::-1] just reverses a string.

[:-1]只是颠倒了一个字符串。

#11


5  

Python 3

--

- - -

Integers (without decimal):

整数(没有小数):

"{:,d}".format(1234567)

“{:d }”.format(1234567)

--

- - -

Floats (with decimal):

浮动(十进制):

"{:,.2f}".format(1234567)

“{:.2f }“.format(1234567)

where the number before f specifies the number of decimal places.

在f前面的数字指定小数位数。

--

- - -

Bonus

奖金

Quick-and-dirty starter function for the Indian lakhs/crores numbering system (12,34,567):

印度lakhs/crores编号系统(12,34,567)的快速和脏启动功能:

https://*.com/a/44832241/4928578

https://*.com/a/44832241/4928578

#12


3  

from Python version 2.6 you can do this:

从Python 2.6版本可以做到这一点:

def format_builtin(n):
    return format(n, ',')

For Python versions < 2.6 and just for your information, here are 2 manual solutions, they turn floats to ints but negative numbers work correctly:

对于Python版本< 2.6,仅供您参考,这里有2个手动解决方案,它们将浮点数转换为ints,但负数工作正确:

def format_number_using_lists(number):
    string = '%d' % number
    result_list = list(string)
    indexes = range(len(string))
    for index in indexes[::-3][1:]:
        if result_list[index] != '-':
            result_list.insert(index+1, ',')
    return ''.join(result_list)

few things to notice here:

这里没有什么值得注意的地方:

  • this line: string = '%d' % number beautifully converts a number to a string, it supports negatives and it drops fractions from floats, making them ints;
  • 这一行:string = '%d' % number漂亮地将一个数字转换成字符串,它支持负数,它从浮动中去掉分数,使它们成为int;
  • this slice indexes[::-3] returns each third item starting from the end, so I used another slice [1:] to remove the very last item cuz I don't need a comma after the last number;
  • 这个切片索引[::-3]从最后返回每个第三项,所以我使用了另一个切片[1:]删除了最后一个条目,因为在最后一个数字之后,我不需要逗号;
  • this conditional if l[index] != '-' is being used to support negative numbers, do not insert a comma after the minus sign.
  • 这个条件如果l[index] != '-'被用来支持负数,在减号后不要插入逗号。

And a more hardcore version:

还有一个更核心的版本:

def format_number_using_generators_and_list_comprehensions(number):
    string = '%d' % number
    generator = reversed( 
        [
            value+',' if (index!=0 and value!='-' and index%3==0) else value
            for index,value in enumerate(reversed(string))
        ]
    )
    return ''.join(generator)

#13


3  

Slightly expanding the answer of Ian Schneider:

稍微扩大Ian Schneider的答案:

If you want to use a custom thousands separator, the simplest solution is:

如果您想使用自定义的数千分隔符,最简单的解决方案是:

'{:,}'.format(value).replace(',', your_custom_thousands_separator)

Examples

'{:,.2f}'.format(123456789.012345).replace(',', ' ')

If you want the German representation like this, it gets a bit more complicated:

如果你想要这样的德语表达,它会变得有点复杂:

('{:,.2f}'.format(123456789.012345)
          .replace(',', ' ')  # 'save' the thousands separators 
          .replace('.', ',')  # dot to comma
          .replace(' ', '.')) # thousand separators to dot

#14


2  

The accepted answer is fine, but I actually prefer format(number,','). Easier for me to interpret and remember.

被接受的答案很好,但实际上我更喜欢格式(数字,',')。更容易理解和记忆。

https://docs.python.org/3/library/functions.html#format

https://docs.python.org/3/library/functions.html格式

#15


1  

Here's one that works for floats too:

这是一个适用于浮动的:

def float2comma(f):
    s = str(abs(f)) # Convert to a string
    decimalposition = s.find(".") # Look for decimal point
    if decimalposition == -1:
        decimalposition = len(s) # If no decimal, then just work from the end
    out = "" 
    for i in range(decimalposition+1, len(s)): # do the decimal
        if not (i-decimalposition-1) % 3 and i-decimalposition-1: out = out+","
        out = out+s[i]      
    if len(out):
        out = "."+out # add the decimal point if necessary
    for i in range(decimalposition-1,-1,-1): # working backwards from decimal point
        if not (decimalposition-i-1) % 3 and decimalposition-i-1: out = ","+out
        out = s[i]+out      
    if f < 0:
        out = "-"+out
    return out

Usage Example:

使用的例子:

>>> float2comma(10000.1111)
'10,000.111,1'
>>> float2comma(656565.122)
'656,565.122'
>>> float2comma(-656565.122)
'-656,565.122'

#16


1  

One liner for Python 2.5+ and Python 3 (positive int only):

Python 2.5+和Python 3的一个内线(仅为正整数):

''.join(reversed([x + (',' if i and not i % 3 else '') for i, x in enumerate(reversed(str(1234567)))]))

#17


1  

I am a Python beginner, but an experienced programmer. I have Python 3.5, so I can just use the comma, but this is nonetheless an interesting programming exercise. Consider the case of an unsigned integer. The most readable Python program for adding thousands separators appears to be:

我是一个Python初学者,但是有经验的程序员。我有Python 3.5,所以我可以用逗号,但这是一个有趣的编程练习。考虑一个无符号整数的情况。增加数千个分隔符的最可读Python程序似乎是:

def add_commas(instr):
    out = [instr[0]]
    for i in range(1, len(instr)):
        if (len(instr) - i) % 3 == 0:
            out.append(',')
        out.append(instr[i])
    return ''.join(out)

It is also possible to use a list comprehension:

还可以使用列表理解:

add_commas(instr):
    rng = reversed(range(1, len(instr) + (len(instr) - 1)//3 + 1))
    out = [',' if j%4 == 0 else instr[-(j - j//4)] for j in rng]
    return ''.join(out)

This is shorter, and could be a one liner, but you will have to do some mental gymnastics to understand why it works. In both cases we get:

这段时间较短,可能是一艘船,但你必须做一些精神上的练习才能理解它为什么会起作用。在这两种情况下,我们得到:

for i in range(1, 11):
    instr = '1234567890'[:i]
    print(instr, add_commas(instr))
1 1
12 12
123 123
1234 1,234
12345 12,345
123456 123,456
1234567 1,234,567
12345678 12,345,678
123456789 123,456,789
1234567890 1,234,567,890

The first version is the more sensible choice, if you want the program to be understood.

第一个版本是更明智的选择,如果你想让程序被理解。

#18


0  

This does money along with the commas

这笔钱和逗号一样。

def format_money(money, presym='$', postsym=''):
    fmt = '%0.2f' % money
    dot = string.find(fmt, '.')
    ret = []
    if money < 0 :
        ret.append('(')
        p0 = 1
    else :
        p0 = 0
    ret.append(presym)
    p1 = (dot-p0) % 3 + p0
    while True :
        ret.append(fmt[p0:p1])
        if p1 == dot : break
        ret.append(',')
        p0 = p1
        p1 += 3
    ret.append(fmt[dot:])   # decimals
    ret.append(postsym)
    if money < 0 : ret.append(')')
    return ''.join(ret)

#19


0  

I have a python 2 and python 3 version of this code. I know that the question was asked for python 2 but now (8 years later lol) people will probably be using python 3.

Python 3 Code:

我有这段代码的python 2和python 3版本。我知道这个问题是关于python 2的,但是现在(8年以后lol)人们可能会使用python 3。Python 3代码:

import random
number = str(random.randint(1, 10000000))
comma_placement = 4
print('The original number is: {}. '.format(number))
while True:
    if len(number) % 3 == 0:
        for i in range(0, len(number) // 3 - 1):
            number = number[0:len(number) - comma_placement + 1] + ',' + number[len(number) - comma_placement + 1:]
            comma_placement = comma_placement + 4
    else:
        for i in range(0, len(number) // 3):
            number = number[0:len(number) - comma_placement + 1] + ',' + number[len(number) - comma_placement + 1:]
    break
print('The new and improved number is: {}'.format(number))        


Python 2 Code: (Edit. The python 2 code isn't working. I am thinking that the syntax is different).

Python代码:2(编辑。python 2代码不起作用。我认为语法是不同的。

import random
number = str(random.randint(1, 10000000))
comma_placement = 4
print 'The original number is: %s.' % (number)
while True:
    if len(number) % 3 == 0:
        for i in range(0, len(number) // 3 - 1):
            number = number[0:len(number) - comma_placement + 1] + ',' + number[len(number) - comma_placement + 1:]
            comma_placement = comma_placement + 4
    else:
        for i in range(0, len(number) // 3):
            number = number[0:len(number) - comma_placement + 1] + ',' + number[len(number) - comma_placement + 1:]
    break
print 'The new and improved number is: %s.' % (number) 

#20


0  

I'm using python 2.5 so I don't have access to the built-in formatting.

我使用的是python 2.5,所以我无法访问内置格式。

I looked at the Django code intcomma (intcomma_recurs in code below) and realized it's inefficient, because it's recursive and also compiling the regex on every run is not a good thing either. This is not necessary an 'issue' as django isn't really THAT focused on this kind of low-level performance. Also, I was expecting a factor of 10 difference in performance, but it's only 3 times slower.

我查看了Django代码int逗号(intcomma_recurs在下面的代码中),并意识到它是低效的,因为它是递归的,而且每次运行时也编译regex也不是一件好事。这并不是一个“问题”,因为django并没有真正关注这种低级的性能。另外,我预计性能会有10个不同,但速度只会慢3倍。

Out of curiosity I implemented a few versions of intcomma to see what the performance advantages are when using regex. My test data concludes a slight advantage for this task, but surprisingly not much at all.

出于好奇,我实现了几个版本的int逗号,以了解使用regex时的性能优势。我的测试数据为这项任务提供了一个微小的优势,但令人惊讶的是,它并没有多少优势。

I also was pleased to see what I suspected: using the reverse xrange approach is unnecessary in the no-regex case, but it does make the code look slightly better at the cost of ~10% performance.

我也很高兴地看到了我的怀疑:在没有regex的情况下,使用反向xrange方法是不必要的,但是它确实使代码看起来稍微好一些,代价是10%的性能。

Also, I assume what you're passing in is a string and looks somewhat like a number. Results undetermined otherwise.

另外,我假设您传入的是一个字符串,看起来有点像一个数字。否则结果待定。

from __future__ import with_statement
from contextlib import contextmanager
import re,time

re_first_num = re.compile(r"\d")
def intcomma_noregex(value):
    end_offset, start_digit, period = len(value),re_first_num.search(value).start(),value.rfind('.')
    if period == -1:
        period=end_offset
    segments,_from_index,leftover = [],0,(period-start_digit) % 3
    for _index in xrange(start_digit+3 if not leftover else start_digit+leftover,period,3):
        segments.append(value[_from_index:_index])
        _from_index=_index
    if not segments:
        return value
    segments.append(value[_from_index:])
    return ','.join(segments)

def intcomma_noregex_reversed(value):
    end_offset, start_digit, period = len(value),re_first_num.search(value).start(),value.rfind('.')
    if period == -1:
        period=end_offset
    _from_index,segments = end_offset,[]
    for _index in xrange(period-3,start_digit,-3):
        segments.append(value[_index:_from_index])
        _from_index=_index
    if not segments:
        return value
    segments.append(value[:_from_index])
    return ','.join(reversed(segments))

re_3digits = re.compile(r'(?<=\d)\d{3}(?!\d)')
def intcomma(value):
    segments,last_endoffset=[],len(value)
    while last_endoffset > 3:
        digit_group = re_3digits.search(value,0,last_endoffset)
        if not digit_group:
            break
        segments.append(value[digit_group.start():last_endoffset])
        last_endoffset=digit_group.start()
    if not segments:
        return value
    if last_endoffset:
        segments.append(value[:last_endoffset])
    return ','.join(reversed(segments))

def intcomma_recurs(value):
    """
    Converts an integer to a string containing commas every three digits.
    For example, 3000 becomes '3,000' and 45000 becomes '45,000'.
    """
    new = re.sub("^(-?\d+)(\d{3})", '\g<1>,\g<2>', str(value))
    if value == new:
        return new
    else:
        return intcomma(new)

@contextmanager
def timed(save_time_func):
    begin=time.time()
    try:
        yield
    finally:
        save_time_func(time.time()-begin)

def testset_xsimple(func):
    func('5')

def testset_simple(func):
    func('567')

def testset_onecomma(func):
    func('567890')

def testset_complex(func):
    func('-1234567.024')

def testset_average(func):
    func('-1234567.024')
    func('567')
    func('5674')

if __name__ == '__main__':
    print 'Test results:'
    for test_data in ('5','567','1234','1234.56','-253892.045'):
        for func in (intcomma,intcomma_noregex,intcomma_noregex_reversed,intcomma_recurs):
            print func.__name__,test_data,func(test_data)
    times=[]
    def overhead(x):
        pass
    for test_run in xrange(1,4):
        for func in (intcomma,intcomma_noregex,intcomma_noregex_reversed,intcomma_recurs,overhead):
            for testset in (testset_xsimple,testset_simple,testset_onecomma,testset_complex,testset_average):
                for x in xrange(1000): # prime the test
                    testset(func)
                with timed(lambda x:times.append(((test_run,func,testset),x))):
                    for x in xrange(50000):
                        testset(func)
    for (test_run,func,testset),_delta in times:
        print test_run,func.__name__,testset.__name__,_delta

And here are the test results:

这里是测试结果:

intcomma 5 5
intcomma_noregex 5 5
intcomma_noregex_reversed 5 5
intcomma_recurs 5 5
intcomma 567 567
intcomma_noregex 567 567
intcomma_noregex_reversed 567 567
intcomma_recurs 567 567
intcomma 1234 1,234
intcomma_noregex 1234 1,234
intcomma_noregex_reversed 1234 1,234
intcomma_recurs 1234 1,234
intcomma 1234.56 1,234.56
intcomma_noregex 1234.56 1,234.56
intcomma_noregex_reversed 1234.56 1,234.56
intcomma_recurs 1234.56 1,234.56
intcomma -253892.045 -253,892.045
intcomma_noregex -253892.045 -253,892.045
intcomma_noregex_reversed -253892.045 -253,892.045
intcomma_recurs -253892.045 -253,892.045
1 intcomma testset_xsimple 0.0410001277924
1 intcomma testset_simple 0.0369999408722
1 intcomma testset_onecomma 0.213000059128
1 intcomma testset_complex 0.296000003815
1 intcomma testset_average 0.503000020981
1 intcomma_noregex testset_xsimple 0.134000062943
1 intcomma_noregex testset_simple 0.134999990463
1 intcomma_noregex testset_onecomma 0.190999984741
1 intcomma_noregex testset_complex 0.209000110626
1 intcomma_noregex testset_average 0.513000011444
1 intcomma_noregex_reversed testset_xsimple 0.124000072479
1 intcomma_noregex_reversed testset_simple 0.12700009346
1 intcomma_noregex_reversed testset_onecomma 0.230000019073
1 intcomma_noregex_reversed testset_complex 0.236999988556
1 intcomma_noregex_reversed testset_average 0.56299996376
1 intcomma_recurs testset_xsimple 0.348000049591
1 intcomma_recurs testset_simple 0.34600019455
1 intcomma_recurs testset_onecomma 0.625
1 intcomma_recurs testset_complex 0.773999929428
1 intcomma_recurs testset_average 1.6890001297
1 overhead testset_xsimple 0.0179998874664
1 overhead testset_simple 0.0190000534058
1 overhead testset_onecomma 0.0190000534058
1 overhead testset_complex 0.0190000534058
1 overhead testset_average 0.0309998989105
2 intcomma testset_xsimple 0.0360000133514
2 intcomma testset_simple 0.0369999408722
2 intcomma testset_onecomma 0.207999944687
2 intcomma testset_complex 0.302000045776
2 intcomma testset_average 0.523000001907
2 intcomma_noregex testset_xsimple 0.139999866486
2 intcomma_noregex testset_simple 0.141000032425
2 intcomma_noregex testset_onecomma 0.203999996185
2 intcomma_noregex testset_complex 0.200999975204
2 intcomma_noregex testset_average 0.523000001907
2 intcomma_noregex_reversed testset_xsimple 0.130000114441
2 intcomma_noregex_reversed testset_simple 0.129999876022
2 intcomma_noregex_reversed testset_onecomma 0.236000061035
2 intcomma_noregex_reversed testset_complex 0.241999864578
2 intcomma_noregex_reversed testset_average 0.582999944687
2 intcomma_recurs testset_xsimple 0.351000070572
2 intcomma_recurs testset_simple 0.352999925613
2 intcomma_recurs testset_onecomma 0.648999929428
2 intcomma_recurs testset_complex 0.808000087738
2 intcomma_recurs testset_average 1.81900000572
2 overhead testset_xsimple 0.0189998149872
2 overhead testset_simple 0.0189998149872
2 overhead testset_onecomma 0.0190000534058
2 overhead testset_complex 0.0179998874664
2 overhead testset_average 0.0299999713898
3 intcomma testset_xsimple 0.0360000133514
3 intcomma testset_simple 0.0360000133514
3 intcomma testset_onecomma 0.210000038147
3 intcomma testset_complex 0.305999994278
3 intcomma testset_average 0.493000030518
3 intcomma_noregex testset_xsimple 0.131999969482
3 intcomma_noregex testset_simple 0.136000156403
3 intcomma_noregex testset_onecomma 0.192999839783
3 intcomma_noregex testset_complex 0.202000141144
3 intcomma_noregex testset_average 0.509999990463
3 intcomma_noregex_reversed testset_xsimple 0.125999927521
3 intcomma_noregex_reversed testset_simple 0.126999855042
3 intcomma_noregex_reversed testset_onecomma 0.235999822617
3 intcomma_noregex_reversed testset_complex 0.243000030518
3 intcomma_noregex_reversed testset_average 0.56200003624
3 intcomma_recurs testset_xsimple 0.337000131607
3 intcomma_recurs testset_simple 0.342000007629
3 intcomma_recurs testset_onecomma 0.609999895096
3 intcomma_recurs testset_complex 0.75
3 intcomma_recurs testset_average 1.68300008774
3 overhead testset_xsimple 0.0189998149872
3 overhead testset_simple 0.018000125885
3 overhead testset_onecomma 0.018000125885
3 overhead testset_complex 0.0179998874664
3 overhead testset_average 0.0299999713898

#21


0  

Just subclass long (or float, or whatever). This is highly practical, because this way you can still use your numbers in math ops (and therefore existing code), but they will all print nicely in your terminal.

只是一个子类(或浮点数,或其他)。这是非常实用的,因为这样您仍然可以在数学操作中使用您的数字(因此也可以使用现有的代码),但是它们都将在您的终端中很好地打印出来。

>>> class number(long):

        def __init__(self, value):
            self = value

        def __repr__(self):
            s = str(self)
            l = [x for x in s if x in '1234567890']
            for x in reversed(range(len(s)-1)[::3]):
                l.insert(-x, ',')
            l = ''.join(l[1:])
            return ('-'+l if self < 0 else l) 

>>> number(-100000)
-100,000
>>> number(-100)
-100
>>> number(-12345)
-12,345
>>> number(928374)
928,374
>>> 345

#22


0  

Italian numbers: thousand separator is a '.'

I solved it this way... for a dictonary

我这样解决了……对于一个dictonary

from random import randint

voci = {
    "immobilizzazioni": randint(200000, 500000),
    "tfr": randint(10000, 25000),
    "ac": randint(150000, 200000),
    "fondo": randint(10500, 22350),
    "debiti": randint(150000, 250000),
    "ratei_attivi": randint(2000, 2500),
    "ratei_passivi": randint(1500, 2600),
    "crediti_v_soci": randint(10000, 30000)
}


testo_rnd2 = """Nell’azienda Hypermax S.p.a. di Bologna le immobilizzazioni valgono {immobilizzazioni:,} €, i debiti per TFR sono pari a {tfr:,} €, l’attivo circolante è di {ac:,} euro, il fondo rischi ed oneri ha un importo pari a {fondo:,} euro, i debiti sono {debiti:,} €, i ratei e risconti attivi sono pari a {ratei_attivi:,} euro, i ratei e risconti passivi sono pari a {ratei_passivi:,} euro. I crediti verso i soci sono pari a {crediti_v_soci:,} euro."""

print(testo_rnd2)

out: le immobilizzazioni valgono 419.168 €. i debiti per TFR sono pari a 13.255 €. l’attivo circolante è di 195.443 euro. il fondo rischi ed oneri ha un importo pari a 13.374 euro. i debiti sono 180.947 €. i ratei e risconti attivi sono pari a 2.271 euro. i ratei e risconti passivi sono pari a 1.864 euro. I crediti verso i soci sono pari a 17.630 euro.

:le immobilizzazioni valgono 419.168€。我每总和生育率debiti园子帕里€13.255。这是195.443欧元。他说:“我有一份13.374欧元的合同。我debiti园子180.947€。我的价格是2.271欧元。我的价格是1欧元兑1.864欧元。我相信我有17.63欧元。

#23


-1  

Here is another variant using a generator function that works for integers:

这里是另一个使用生成器函数的变量,它适用于整数:

def ncomma(num):
    def _helper(num):
        # assert isinstance(numstr, basestring)
        numstr = '%d' % num
        for ii, digit in enumerate(reversed(numstr)):
            if ii and ii % 3 == 0 and digit.isdigit():
                yield ','
            yield digit

    return ''.join(reversed([n for n in _helper(num)]))

And here's a test:

这是一个测试:

>>> for i in (0, 99, 999, 9999, 999999, 1000000, -1, -111, -1111, -111111, -1000000):
...     print i, ncomma(i)
... 
0 0
99 99
999 999
9999 9,999
999999 999,999
1000000 1,000,000
-1 -1
-111 -111
-1111 -1,111
-111111 -111,111
-1000000 -1,000,000

#24


-1  

I prefer the locale-based solution for real projects, but I think the approach with the use of slice assignment should be mentioned here:

我更喜欢实际项目的基于区域的解决方案,但是我认为应该在这里提到使用slice赋值的方法:

def format_money(f, delimiter=',', frac_digits=2):

    negative_fix = int(f < 0)

    s = '%.*f' % (frac_digits, f)
    if len(s) < 5 + frac_digits + negative_fix:
        return s

    l = list(s)
    l_fix = l[negative_fix:]
    p = len(l_fix) - frac_digits - 5
    l_fix[p::-3] = [i + delimiter for i in l_fix[p::-3]]

    return ''.join(l[:negative_fix] + l_fix)

Gist with doctests is here - https://gist.github.com/ei-grad/b290dc761ae253af69438bbb94d82683

使用doctest的要点是这里- https://gist.github.com/ei-grad/b290dc761ae253af694d82683。

#25


-6  

For floats:

浮点数:

float(filter(lambda x: x!=',', '1,234.52'))
# returns 1234.52

For ints:

整数:

int(filter(lambda x: x!=',', '1,234'))
# returns 1234

#26


-7  

If you don't want to depend on any external libraries:

如果您不想依赖任何外部库:

 s = str(1234567)
 print ','.join([s[::-1][k:k+3][::-1] for k in xrange(len(s)-1, -1, -3)])

This works only for non-negative integers.

这只适用于非负整数。

#1


1266  

For Python ≥ 2.7:

对于Python≥2.7:

"{:,}".format(value)

Per Format Specification Mini-Language,

每个迷你语言格式规范,

The ',' option signals the use of a comma for a thousands separator. For a locale aware separator, use the 'n' integer presentation type instead.

“,”选项表示在数千个分隔符中使用逗号。对于语言环境敏感的分隔符,请使用“n”整数表示类型。

#2


259  

I got this to work:

我让它工作:

>>> import locale
>>> locale.setlocale(locale.LC_ALL, 'en_US')
'en_US'
>>> locale.format("%d", 1255000, grouping=True)
'1,255,000'

Sure, you don't need internationalization support, but it's clear, concise, and uses a built-in library.

当然,您不需要国际化支持,但它是清晰、简洁的,并且使用了内置的库。

P.S. That "%d" is the usual %-style formatter. You can have only one formatter, but it can be whatever you need in terms of field width and precision settings.

“%d”是常见的%样式格式化程序。您只能有一个格式化程序,但它可以是任何您需要的字段宽度和精度设置。

P.P.S. If you can't get locale to work, I'd suggest a modified version of Mark's answer:

P.P.S.如果你不能让现场工作,我建议你修改一下马克的答案:

def intWithCommas(x):
    if type(x) not in [type(0), type(0L)]:
        raise TypeError("Parameter must be an integer.")
    if x < 0:
        return '-' + intWithCommas(-x)
    result = ''
    while x >= 1000:
        x, r = divmod(x, 1000)
        result = ",%03d%s" % (r, result)
    return "%d%s" % (x, result)

Recursion is useful for the negative case, but one recursion per comma seems a bit excessive to me.

递归对于负的情况很有用,但是每个逗号的递归似乎有点过分。

#3


89  

Here is the locale grouping code after removing irrelevant parts and cleaning it up a little:

这里是地区分组代码,删除不相关的部分,并清理它一点:

(The following only works for integers)

(以下仅适用于整数)

def group(number):
    s = '%d' % number
    groups = []
    while s and s[-1].isdigit():
        groups.append(s[-3:])
        s = s[:-3]
    return s + ','.join(reversed(groups))

>>> group(-23432432434.34)
'-23,432,432,434'

There are already some good answers in here. I just want to add this for future reference. In python 2.7 there is going to be a format specifier for thousands separator. According to python docs it works like this

这里已经有一些不错的答案了。我只是想补充一下,以备将来参考。在python 2.7中,将有一个用于数千个分隔符的格式说明符。根据python文档,它是这样工作的。

>>> '{:20,.2f}'.format(f)
'18,446,744,073,709,551,616.00'

In python3.1 you can do the same thing like this:

在python3.1中,你可以这样做:

>>> format(1234567, ',d')
'1,234,567'

#4


84  

For inefficiency and unreadability it's hard to beat:

对于低效率和不可读性来说,它很难被击败:

>>> import itertools
>>> s = '-1234567'
>>> ','.join(["%s%s%s" % (x[0], x[1] or '', x[2] or '') for x in itertools.izip_longest(s[::-1][::3], s[::-1][1::3], s[::-1][2::3])])[::-1].replace('-,','-')

#5


31  

Here's a one-line regex replacement:

这是一个单线regex替换:

re.sub("(\d)(?=(\d{3})+(?!\d))", r"\1,", "%d" % val)

Works only for inegral outputs:

只适用于不适当的输出:

import re
val = 1234567890
re.sub("(\d)(?=(\d{3})+(?!\d))", r"\1,", "%d" % val)
# Returns: '1,234,567,890'

val = 1234567890.1234567890
# Returns: '1,234,567,890'

Or for floats with less than 4 digits, change the format specifier to %.3f:

或者对于小于4位数的浮点数,将格式说明符更改为%.3f:

re.sub("(\d)(?=(\d{3})+(?!\d))", r"\1,", "%.3f" % val)
# Returns: '1,234,567,890.123'

NB: Doesn't work correctly with more than three decimal digits as it will attempt to group the decimal part:

NB:不能正确地使用超过3位小数,因为它将尝试将小数部分分组:

re.sub("(\d)(?=(\d{3})+(?!\d))", r"\1,", "%.5f" % val)
# Returns: '1,234,567,890.12,346'

How it works

Let's break it down:

让我们分解:

re.sub(pattern, repl, string)

pattern = \
    "(\d)           # Find one digit...
     (?=            # that is followed by...
         (\d{3})+   # one or more groups of three digits...
         (?!\d)     # which are not followed by any more digits.
     )",

repl = \
    r"\1,",         # Replace that one digit by itself, followed by a comma,
                    # and continue looking for more matches later in the string.
                    # (re.sub() replaces all matches it finds in the input)

string = \
    "%d" % val      # Format the string as a decimal to begin with

#6


15  

You can also use '{:n}'.format( value ) for a locale representation. I think this is the simpliest way for a locale solution.

您还可以使用“{:n}”。格式(值)用于区域设置表示。我认为这是语言环境解决方案最简单的方法。

For more information, search for thousands in Python DOC.

有关更多信息,请在Python文档中搜索数千条。

For currency, you can use locale.currency, setting the flag grouping:

对于货币,您可以使用区域设置。货币,设置国旗分组:

Code

代码

import locale

locale.setlocale( locale.LC_ALL, '' )
locale.currency( 1234567.89, grouping = True )

Output

输出

'Portuguese_Brazil.1252'
'R$ 1.234.567,89'

#7


14  

This is what I do for floats. Although, honestly, I'm not sure which versions it works for - I'm using 2.7:

这是我为浮点数所做的。虽然,老实说,我不确定它适用于哪个版本——我使用的是2.7:

my_number = 4385893.382939491

my_string = '{:0,.2f}'.format(my_number)

Returns: 4,385,893.38

返回:4385893 .38点

Update: I recently had an issue with this format (couldn't tell you the exact reason), but was able to fix it by dropping the 0:

更新:我最近遇到了这个格式的问题(不能告诉您确切的原因),但是可以通过删除0来修复它:

my_string = '{:,.2f}'.format(my_number)

#8


12  

I'm surprised that no one has mentioned that you can do this with f-strings in Python 3.6 as easy as this:

我很惊讶没有人提到你可以用Python 3.6中的f-string来做这个:

>>> num = 10000000
>>> print(f"{num:,d}")
10,000,000

... where the part after the colon is the format specifier. The comma is the separator character you want, so f"{num:_d}" uses underscores instead of a comma.

…在冒号后面的部分是格式说明符。逗号是您想要的分隔符,所以f“{num:_d}”使用下划线而不是逗号。

This is equivalent of using format(num, ",d") for older versions of python 3.

这相当于使用了旧版本的python 3的格式(num,“d”)。

#9


10  

I'm sure there must be a standard library function for this, but it was fun to try to write it myself using recursion so here's what I came up with:

我确信这里面一定有一个标准的库函数,但是尝试用递归来写它是很有趣的所以这就是我想到的:

def intToStringWithCommas(x):
    if type(x) is not int and type(x) is not long:
        raise TypeError("Not an integer!")
    if x < 0:
        return '-' + intToStringWithCommas(-x)
    elif x < 1000:
        return str(x)
    else:
        return intToStringWithCommas(x / 1000) + ',' + '%03d' % (x % 1000)

Having said that, if someone else does find a standard way to do it, you should use that instead.

话虽如此,如果别人确实找到了一种标准的方法,你应该用它来代替。

#10


8  

From the comments to activestate recipe 498181 I reworked this:

从评论到activestate recipe 498181,我重新做了这个:

import re
def thous(x, sep=',', dot='.'):
    num, _, frac = str(x).partition(dot)
    num = re.sub(r'(\d{3})(?=\d)', r'\1'+sep, num[::-1])[::-1]
    if frac:
        num += dot + frac
    return num

It uses the regular expressions feature: lookahead i.e. (?=\d) to make sure only groups of three digits that have a digit 'after' them get a comma. I say 'after' because the string is reverse at this point.

它使用正则表达式特性:lookahead (?=\d),以确保只有三个数字的组在得到一个逗号之后才有一个数字。我说" after "因为这个字符串在这里是反向的。

[::-1] just reverses a string.

[:-1]只是颠倒了一个字符串。

#11


5  

Python 3

--

- - -

Integers (without decimal):

整数(没有小数):

"{:,d}".format(1234567)

“{:d }”.format(1234567)

--

- - -

Floats (with decimal):

浮动(十进制):

"{:,.2f}".format(1234567)

“{:.2f }“.format(1234567)

where the number before f specifies the number of decimal places.

在f前面的数字指定小数位数。

--

- - -

Bonus

奖金

Quick-and-dirty starter function for the Indian lakhs/crores numbering system (12,34,567):

印度lakhs/crores编号系统(12,34,567)的快速和脏启动功能:

https://*.com/a/44832241/4928578

https://*.com/a/44832241/4928578

#12


3  

from Python version 2.6 you can do this:

从Python 2.6版本可以做到这一点:

def format_builtin(n):
    return format(n, ',')

For Python versions < 2.6 and just for your information, here are 2 manual solutions, they turn floats to ints but negative numbers work correctly:

对于Python版本< 2.6,仅供您参考,这里有2个手动解决方案,它们将浮点数转换为ints,但负数工作正确:

def format_number_using_lists(number):
    string = '%d' % number
    result_list = list(string)
    indexes = range(len(string))
    for index in indexes[::-3][1:]:
        if result_list[index] != '-':
            result_list.insert(index+1, ',')
    return ''.join(result_list)

few things to notice here:

这里没有什么值得注意的地方:

  • this line: string = '%d' % number beautifully converts a number to a string, it supports negatives and it drops fractions from floats, making them ints;
  • 这一行:string = '%d' % number漂亮地将一个数字转换成字符串,它支持负数,它从浮动中去掉分数,使它们成为int;
  • this slice indexes[::-3] returns each third item starting from the end, so I used another slice [1:] to remove the very last item cuz I don't need a comma after the last number;
  • 这个切片索引[::-3]从最后返回每个第三项,所以我使用了另一个切片[1:]删除了最后一个条目,因为在最后一个数字之后,我不需要逗号;
  • this conditional if l[index] != '-' is being used to support negative numbers, do not insert a comma after the minus sign.
  • 这个条件如果l[index] != '-'被用来支持负数,在减号后不要插入逗号。

And a more hardcore version:

还有一个更核心的版本:

def format_number_using_generators_and_list_comprehensions(number):
    string = '%d' % number
    generator = reversed( 
        [
            value+',' if (index!=0 and value!='-' and index%3==0) else value
            for index,value in enumerate(reversed(string))
        ]
    )
    return ''.join(generator)

#13


3  

Slightly expanding the answer of Ian Schneider:

稍微扩大Ian Schneider的答案:

If you want to use a custom thousands separator, the simplest solution is:

如果您想使用自定义的数千分隔符,最简单的解决方案是:

'{:,}'.format(value).replace(',', your_custom_thousands_separator)

Examples

'{:,.2f}'.format(123456789.012345).replace(',', ' ')

If you want the German representation like this, it gets a bit more complicated:

如果你想要这样的德语表达,它会变得有点复杂:

('{:,.2f}'.format(123456789.012345)
          .replace(',', ' ')  # 'save' the thousands separators 
          .replace('.', ',')  # dot to comma
          .replace(' ', '.')) # thousand separators to dot

#14


2  

The accepted answer is fine, but I actually prefer format(number,','). Easier for me to interpret and remember.

被接受的答案很好,但实际上我更喜欢格式(数字,',')。更容易理解和记忆。

https://docs.python.org/3/library/functions.html#format

https://docs.python.org/3/library/functions.html格式

#15


1  

Here's one that works for floats too:

这是一个适用于浮动的:

def float2comma(f):
    s = str(abs(f)) # Convert to a string
    decimalposition = s.find(".") # Look for decimal point
    if decimalposition == -1:
        decimalposition = len(s) # If no decimal, then just work from the end
    out = "" 
    for i in range(decimalposition+1, len(s)): # do the decimal
        if not (i-decimalposition-1) % 3 and i-decimalposition-1: out = out+","
        out = out+s[i]      
    if len(out):
        out = "."+out # add the decimal point if necessary
    for i in range(decimalposition-1,-1,-1): # working backwards from decimal point
        if not (decimalposition-i-1) % 3 and decimalposition-i-1: out = ","+out
        out = s[i]+out      
    if f < 0:
        out = "-"+out
    return out

Usage Example:

使用的例子:

>>> float2comma(10000.1111)
'10,000.111,1'
>>> float2comma(656565.122)
'656,565.122'
>>> float2comma(-656565.122)
'-656,565.122'

#16


1  

One liner for Python 2.5+ and Python 3 (positive int only):

Python 2.5+和Python 3的一个内线(仅为正整数):

''.join(reversed([x + (',' if i and not i % 3 else '') for i, x in enumerate(reversed(str(1234567)))]))

#17


1  

I am a Python beginner, but an experienced programmer. I have Python 3.5, so I can just use the comma, but this is nonetheless an interesting programming exercise. Consider the case of an unsigned integer. The most readable Python program for adding thousands separators appears to be:

我是一个Python初学者,但是有经验的程序员。我有Python 3.5,所以我可以用逗号,但这是一个有趣的编程练习。考虑一个无符号整数的情况。增加数千个分隔符的最可读Python程序似乎是:

def add_commas(instr):
    out = [instr[0]]
    for i in range(1, len(instr)):
        if (len(instr) - i) % 3 == 0:
            out.append(',')
        out.append(instr[i])
    return ''.join(out)

It is also possible to use a list comprehension:

还可以使用列表理解:

add_commas(instr):
    rng = reversed(range(1, len(instr) + (len(instr) - 1)//3 + 1))
    out = [',' if j%4 == 0 else instr[-(j - j//4)] for j in rng]
    return ''.join(out)

This is shorter, and could be a one liner, but you will have to do some mental gymnastics to understand why it works. In both cases we get:

这段时间较短,可能是一艘船,但你必须做一些精神上的练习才能理解它为什么会起作用。在这两种情况下,我们得到:

for i in range(1, 11):
    instr = '1234567890'[:i]
    print(instr, add_commas(instr))
1 1
12 12
123 123
1234 1,234
12345 12,345
123456 123,456
1234567 1,234,567
12345678 12,345,678
123456789 123,456,789
1234567890 1,234,567,890

The first version is the more sensible choice, if you want the program to be understood.

第一个版本是更明智的选择,如果你想让程序被理解。

#18


0  

This does money along with the commas

这笔钱和逗号一样。

def format_money(money, presym='$', postsym=''):
    fmt = '%0.2f' % money
    dot = string.find(fmt, '.')
    ret = []
    if money < 0 :
        ret.append('(')
        p0 = 1
    else :
        p0 = 0
    ret.append(presym)
    p1 = (dot-p0) % 3 + p0
    while True :
        ret.append(fmt[p0:p1])
        if p1 == dot : break
        ret.append(',')
        p0 = p1
        p1 += 3
    ret.append(fmt[dot:])   # decimals
    ret.append(postsym)
    if money < 0 : ret.append(')')
    return ''.join(ret)

#19


0  

I have a python 2 and python 3 version of this code. I know that the question was asked for python 2 but now (8 years later lol) people will probably be using python 3.

Python 3 Code:

我有这段代码的python 2和python 3版本。我知道这个问题是关于python 2的,但是现在(8年以后lol)人们可能会使用python 3。Python 3代码:

import random
number = str(random.randint(1, 10000000))
comma_placement = 4
print('The original number is: {}. '.format(number))
while True:
    if len(number) % 3 == 0:
        for i in range(0, len(number) // 3 - 1):
            number = number[0:len(number) - comma_placement + 1] + ',' + number[len(number) - comma_placement + 1:]
            comma_placement = comma_placement + 4
    else:
        for i in range(0, len(number) // 3):
            number = number[0:len(number) - comma_placement + 1] + ',' + number[len(number) - comma_placement + 1:]
    break
print('The new and improved number is: {}'.format(number))        


Python 2 Code: (Edit. The python 2 code isn't working. I am thinking that the syntax is different).

Python代码:2(编辑。python 2代码不起作用。我认为语法是不同的。

import random
number = str(random.randint(1, 10000000))
comma_placement = 4
print 'The original number is: %s.' % (number)
while True:
    if len(number) % 3 == 0:
        for i in range(0, len(number) // 3 - 1):
            number = number[0:len(number) - comma_placement + 1] + ',' + number[len(number) - comma_placement + 1:]
            comma_placement = comma_placement + 4
    else:
        for i in range(0, len(number) // 3):
            number = number[0:len(number) - comma_placement + 1] + ',' + number[len(number) - comma_placement + 1:]
    break
print 'The new and improved number is: %s.' % (number) 

#20


0  

I'm using python 2.5 so I don't have access to the built-in formatting.

我使用的是python 2.5,所以我无法访问内置格式。

I looked at the Django code intcomma (intcomma_recurs in code below) and realized it's inefficient, because it's recursive and also compiling the regex on every run is not a good thing either. This is not necessary an 'issue' as django isn't really THAT focused on this kind of low-level performance. Also, I was expecting a factor of 10 difference in performance, but it's only 3 times slower.

我查看了Django代码int逗号(intcomma_recurs在下面的代码中),并意识到它是低效的,因为它是递归的,而且每次运行时也编译regex也不是一件好事。这并不是一个“问题”,因为django并没有真正关注这种低级的性能。另外,我预计性能会有10个不同,但速度只会慢3倍。

Out of curiosity I implemented a few versions of intcomma to see what the performance advantages are when using regex. My test data concludes a slight advantage for this task, but surprisingly not much at all.

出于好奇,我实现了几个版本的int逗号,以了解使用regex时的性能优势。我的测试数据为这项任务提供了一个微小的优势,但令人惊讶的是,它并没有多少优势。

I also was pleased to see what I suspected: using the reverse xrange approach is unnecessary in the no-regex case, but it does make the code look slightly better at the cost of ~10% performance.

我也很高兴地看到了我的怀疑:在没有regex的情况下,使用反向xrange方法是不必要的,但是它确实使代码看起来稍微好一些,代价是10%的性能。

Also, I assume what you're passing in is a string and looks somewhat like a number. Results undetermined otherwise.

另外,我假设您传入的是一个字符串,看起来有点像一个数字。否则结果待定。

from __future__ import with_statement
from contextlib import contextmanager
import re,time

re_first_num = re.compile(r"\d")
def intcomma_noregex(value):
    end_offset, start_digit, period = len(value),re_first_num.search(value).start(),value.rfind('.')
    if period == -1:
        period=end_offset
    segments,_from_index,leftover = [],0,(period-start_digit) % 3
    for _index in xrange(start_digit+3 if not leftover else start_digit+leftover,period,3):
        segments.append(value[_from_index:_index])
        _from_index=_index
    if not segments:
        return value
    segments.append(value[_from_index:])
    return ','.join(segments)

def intcomma_noregex_reversed(value):
    end_offset, start_digit, period = len(value),re_first_num.search(value).start(),value.rfind('.')
    if period == -1:
        period=end_offset
    _from_index,segments = end_offset,[]
    for _index in xrange(period-3,start_digit,-3):
        segments.append(value[_index:_from_index])
        _from_index=_index
    if not segments:
        return value
    segments.append(value[:_from_index])
    return ','.join(reversed(segments))

re_3digits = re.compile(r'(?<=\d)\d{3}(?!\d)')
def intcomma(value):
    segments,last_endoffset=[],len(value)
    while last_endoffset > 3:
        digit_group = re_3digits.search(value,0,last_endoffset)
        if not digit_group:
            break
        segments.append(value[digit_group.start():last_endoffset])
        last_endoffset=digit_group.start()
    if not segments:
        return value
    if last_endoffset:
        segments.append(value[:last_endoffset])
    return ','.join(reversed(segments))

def intcomma_recurs(value):
    """
    Converts an integer to a string containing commas every three digits.
    For example, 3000 becomes '3,000' and 45000 becomes '45,000'.
    """
    new = re.sub("^(-?\d+)(\d{3})", '\g<1>,\g<2>', str(value))
    if value == new:
        return new
    else:
        return intcomma(new)

@contextmanager
def timed(save_time_func):
    begin=time.time()
    try:
        yield
    finally:
        save_time_func(time.time()-begin)

def testset_xsimple(func):
    func('5')

def testset_simple(func):
    func('567')

def testset_onecomma(func):
    func('567890')

def testset_complex(func):
    func('-1234567.024')

def testset_average(func):
    func('-1234567.024')
    func('567')
    func('5674')

if __name__ == '__main__':
    print 'Test results:'
    for test_data in ('5','567','1234','1234.56','-253892.045'):
        for func in (intcomma,intcomma_noregex,intcomma_noregex_reversed,intcomma_recurs):
            print func.__name__,test_data,func(test_data)
    times=[]
    def overhead(x):
        pass
    for test_run in xrange(1,4):
        for func in (intcomma,intcomma_noregex,intcomma_noregex_reversed,intcomma_recurs,overhead):
            for testset in (testset_xsimple,testset_simple,testset_onecomma,testset_complex,testset_average):
                for x in xrange(1000): # prime the test
                    testset(func)
                with timed(lambda x:times.append(((test_run,func,testset),x))):
                    for x in xrange(50000):
                        testset(func)
    for (test_run,func,testset),_delta in times:
        print test_run,func.__name__,testset.__name__,_delta

And here are the test results:

这里是测试结果:

intcomma 5 5
intcomma_noregex 5 5
intcomma_noregex_reversed 5 5
intcomma_recurs 5 5
intcomma 567 567
intcomma_noregex 567 567
intcomma_noregex_reversed 567 567
intcomma_recurs 567 567
intcomma 1234 1,234
intcomma_noregex 1234 1,234
intcomma_noregex_reversed 1234 1,234
intcomma_recurs 1234 1,234
intcomma 1234.56 1,234.56
intcomma_noregex 1234.56 1,234.56
intcomma_noregex_reversed 1234.56 1,234.56
intcomma_recurs 1234.56 1,234.56
intcomma -253892.045 -253,892.045
intcomma_noregex -253892.045 -253,892.045
intcomma_noregex_reversed -253892.045 -253,892.045
intcomma_recurs -253892.045 -253,892.045
1 intcomma testset_xsimple 0.0410001277924
1 intcomma testset_simple 0.0369999408722
1 intcomma testset_onecomma 0.213000059128
1 intcomma testset_complex 0.296000003815
1 intcomma testset_average 0.503000020981
1 intcomma_noregex testset_xsimple 0.134000062943
1 intcomma_noregex testset_simple 0.134999990463
1 intcomma_noregex testset_onecomma 0.190999984741
1 intcomma_noregex testset_complex 0.209000110626
1 intcomma_noregex testset_average 0.513000011444
1 intcomma_noregex_reversed testset_xsimple 0.124000072479
1 intcomma_noregex_reversed testset_simple 0.12700009346
1 intcomma_noregex_reversed testset_onecomma 0.230000019073
1 intcomma_noregex_reversed testset_complex 0.236999988556
1 intcomma_noregex_reversed testset_average 0.56299996376
1 intcomma_recurs testset_xsimple 0.348000049591
1 intcomma_recurs testset_simple 0.34600019455
1 intcomma_recurs testset_onecomma 0.625
1 intcomma_recurs testset_complex 0.773999929428
1 intcomma_recurs testset_average 1.6890001297
1 overhead testset_xsimple 0.0179998874664
1 overhead testset_simple 0.0190000534058
1 overhead testset_onecomma 0.0190000534058
1 overhead testset_complex 0.0190000534058
1 overhead testset_average 0.0309998989105
2 intcomma testset_xsimple 0.0360000133514
2 intcomma testset_simple 0.0369999408722
2 intcomma testset_onecomma 0.207999944687
2 intcomma testset_complex 0.302000045776
2 intcomma testset_average 0.523000001907
2 intcomma_noregex testset_xsimple 0.139999866486
2 intcomma_noregex testset_simple 0.141000032425
2 intcomma_noregex testset_onecomma 0.203999996185
2 intcomma_noregex testset_complex 0.200999975204
2 intcomma_noregex testset_average 0.523000001907
2 intcomma_noregex_reversed testset_xsimple 0.130000114441
2 intcomma_noregex_reversed testset_simple 0.129999876022
2 intcomma_noregex_reversed testset_onecomma 0.236000061035
2 intcomma_noregex_reversed testset_complex 0.241999864578
2 intcomma_noregex_reversed testset_average 0.582999944687
2 intcomma_recurs testset_xsimple 0.351000070572
2 intcomma_recurs testset_simple 0.352999925613
2 intcomma_recurs testset_onecomma 0.648999929428
2 intcomma_recurs testset_complex 0.808000087738
2 intcomma_recurs testset_average 1.81900000572
2 overhead testset_xsimple 0.0189998149872
2 overhead testset_simple 0.0189998149872
2 overhead testset_onecomma 0.0190000534058
2 overhead testset_complex 0.0179998874664
2 overhead testset_average 0.0299999713898
3 intcomma testset_xsimple 0.0360000133514
3 intcomma testset_simple 0.0360000133514
3 intcomma testset_onecomma 0.210000038147
3 intcomma testset_complex 0.305999994278
3 intcomma testset_average 0.493000030518
3 intcomma_noregex testset_xsimple 0.131999969482
3 intcomma_noregex testset_simple 0.136000156403
3 intcomma_noregex testset_onecomma 0.192999839783
3 intcomma_noregex testset_complex 0.202000141144
3 intcomma_noregex testset_average 0.509999990463
3 intcomma_noregex_reversed testset_xsimple 0.125999927521
3 intcomma_noregex_reversed testset_simple 0.126999855042
3 intcomma_noregex_reversed testset_onecomma 0.235999822617
3 intcomma_noregex_reversed testset_complex 0.243000030518
3 intcomma_noregex_reversed testset_average 0.56200003624
3 intcomma_recurs testset_xsimple 0.337000131607
3 intcomma_recurs testset_simple 0.342000007629
3 intcomma_recurs testset_onecomma 0.609999895096
3 intcomma_recurs testset_complex 0.75
3 intcomma_recurs testset_average 1.68300008774
3 overhead testset_xsimple 0.0189998149872
3 overhead testset_simple 0.018000125885
3 overhead testset_onecomma 0.018000125885
3 overhead testset_complex 0.0179998874664
3 overhead testset_average 0.0299999713898

#21


0  

Just subclass long (or float, or whatever). This is highly practical, because this way you can still use your numbers in math ops (and therefore existing code), but they will all print nicely in your terminal.

只是一个子类(或浮点数,或其他)。这是非常实用的,因为这样您仍然可以在数学操作中使用您的数字(因此也可以使用现有的代码),但是它们都将在您的终端中很好地打印出来。

>>> class number(long):

        def __init__(self, value):
            self = value

        def __repr__(self):
            s = str(self)
            l = [x for x in s if x in '1234567890']
            for x in reversed(range(len(s)-1)[::3]):
                l.insert(-x, ',')
            l = ''.join(l[1:])
            return ('-'+l if self < 0 else l) 

>>> number(-100000)
-100,000
>>> number(-100)
-100
>>> number(-12345)
-12,345
>>> number(928374)
928,374
>>> 345

#22


0  

Italian numbers: thousand separator is a '.'

I solved it this way... for a dictonary

我这样解决了……对于一个dictonary

from random import randint

voci = {
    "immobilizzazioni": randint(200000, 500000),
    "tfr": randint(10000, 25000),
    "ac": randint(150000, 200000),
    "fondo": randint(10500, 22350),
    "debiti": randint(150000, 250000),
    "ratei_attivi": randint(2000, 2500),
    "ratei_passivi": randint(1500, 2600),
    "crediti_v_soci": randint(10000, 30000)
}


testo_rnd2 = """Nell’azienda Hypermax S.p.a. di Bologna le immobilizzazioni valgono {immobilizzazioni:,} €, i debiti per TFR sono pari a {tfr:,} €, l’attivo circolante è di {ac:,} euro, il fondo rischi ed oneri ha un importo pari a {fondo:,} euro, i debiti sono {debiti:,} €, i ratei e risconti attivi sono pari a {ratei_attivi:,} euro, i ratei e risconti passivi sono pari a {ratei_passivi:,} euro. I crediti verso i soci sono pari a {crediti_v_soci:,} euro."""

print(testo_rnd2)

out: le immobilizzazioni valgono 419.168 €. i debiti per TFR sono pari a 13.255 €. l’attivo circolante è di 195.443 euro. il fondo rischi ed oneri ha un importo pari a 13.374 euro. i debiti sono 180.947 €. i ratei e risconti attivi sono pari a 2.271 euro. i ratei e risconti passivi sono pari a 1.864 euro. I crediti verso i soci sono pari a 17.630 euro.

:le immobilizzazioni valgono 419.168€。我每总和生育率debiti园子帕里€13.255。这是195.443欧元。他说:“我有一份13.374欧元的合同。我debiti园子180.947€。我的价格是2.271欧元。我的价格是1欧元兑1.864欧元。我相信我有17.63欧元。

#23


-1  

Here is another variant using a generator function that works for integers:

这里是另一个使用生成器函数的变量,它适用于整数:

def ncomma(num):
    def _helper(num):
        # assert isinstance(numstr, basestring)
        numstr = '%d' % num
        for ii, digit in enumerate(reversed(numstr)):
            if ii and ii % 3 == 0 and digit.isdigit():
                yield ','
            yield digit

    return ''.join(reversed([n for n in _helper(num)]))

And here's a test:

这是一个测试:

>>> for i in (0, 99, 999, 9999, 999999, 1000000, -1, -111, -1111, -111111, -1000000):
...     print i, ncomma(i)
... 
0 0
99 99
999 999
9999 9,999
999999 999,999
1000000 1,000,000
-1 -1
-111 -111
-1111 -1,111
-111111 -111,111
-1000000 -1,000,000

#24


-1  

I prefer the locale-based solution for real projects, but I think the approach with the use of slice assignment should be mentioned here:

我更喜欢实际项目的基于区域的解决方案,但是我认为应该在这里提到使用slice赋值的方法:

def format_money(f, delimiter=',', frac_digits=2):

    negative_fix = int(f < 0)

    s = '%.*f' % (frac_digits, f)
    if len(s) < 5 + frac_digits + negative_fix:
        return s

    l = list(s)
    l_fix = l[negative_fix:]
    p = len(l_fix) - frac_digits - 5
    l_fix[p::-3] = [i + delimiter for i in l_fix[p::-3]]

    return ''.join(l[:negative_fix] + l_fix)

Gist with doctests is here - https://gist.github.com/ei-grad/b290dc761ae253af69438bbb94d82683

使用doctest的要点是这里- https://gist.github.com/ei-grad/b290dc761ae253af694d82683。

#25


-6  

For floats:

浮点数:

float(filter(lambda x: x!=',', '1,234.52'))
# returns 1234.52

For ints:

整数:

int(filter(lambda x: x!=',', '1,234'))
# returns 1234

#26


-7  

If you don't want to depend on any external libraries:

如果您不想依赖任何外部库:

 s = str(1234567)
 print ','.join([s[::-1][k:k+3][::-1] for k in xrange(len(s)-1, -1, -3)])

This works only for non-negative integers.

这只适用于非负整数。