如何使用逗号作为千分隔符打印数字

如何打印带有逗号的整数作为数千个分隔符?

1234567   ⟶   1,234,567

在句号和逗号之间进行选择不需要特定于语言环境。

767594 次浏览

我确信必须有一个标准库函数,但是尝试使用递归自己编写它很有趣,所以这是我想出的:

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)

话虽如此,如果其他人确实找到了一种标准的方法来做到这一点,你应该使用它。

我得到了这个工作:

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

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

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

P. P. S.如果你不能让locale起作用,我建议修改马克的回答:

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)

递归对于否定情况很有用,但是每个逗号一个递归对我来说似乎有点过分。

只需子类long(或float,或其他)。这非常实用,因为这样您仍然可以在数学运算(以及现有代码)中使用您的数字,但它们都将在您的终端中很好地打印出来。

>>> 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

这是删除不相关部分并稍微清理后的语言环境分组代码:

(以下仅适用于整数)

def group(number):s = '%d' % numbergroups = []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'

这里已经有了一些很好的答案。我只想添加这个以供将来参考。在python 2.7中,将有一个数千分隔符的格式说明符。根据python文档,它的工作原理是这样的

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

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

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

这里有一个也适用于浮点数:

def float2comma(f):s = str(abs(f)) # Convert to a stringdecimalposition = s.find(".") # Look for decimal pointif decimalposition == -1:decimalposition = len(s) # If no decimal, then just work from the endout = ""for i in range(decimalposition+1, len(s)): # do the decimalif 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 necessaryfor i in range(decimalposition-1,-1,-1): # working backwards from decimal pointif not (decimalposition-i-1) % 3 and decimalposition-i-1: out = ","+outout = s[i]+outif f < 0:out = "-"+outreturn out

使用示例:

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

评论数到激活配方498181我重新设计了这个:

import redef 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 + fracreturn num

它使用正则表达式特性:向前看(?=\d)来确保只有三个数字的组具有“之后”的数字才能获得逗号。我说“之后”是因为此时字符串是反向的。

[::-1]只是反转一个字符串。

对于浮动:

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

对于int:

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

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

>>> 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('-,','-')

区域设置未知

'{:,}'.format(value)  # For Python ≥2.7f'{value:,}'          # For Python ≥3.6

区域感知

import localelocale.setlocale(locale.LC_ALL, '')  # Use '' for auto, or force e.g. to 'en_US.UTF-8'
'{:n}'.format(value)  # For Python ≥2.7f'{value:n}'          # For Python ≥3.6

参考

格式规范小语言

','选项表示千位分隔符使用逗号。对于区域设置感知分隔符,请改用'n'整数表示类型。

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

我查看了Django的intcoma代码(intcomma_recurs在下面的代码中),意识到它效率低下,因为它是递归的,并且在每次运行时编译正则表达式也不是一件好事。这不是一个必要的“问题”,因为Django并不真正关注这种低级性能。此外,我预计性能会有10倍的差异,但它只慢3倍。

出于好奇,我实现了几个版本的intcoma,看看使用regex时的性能优势是什么。我的测试数据得出结论,这项任务有一点优势,但令人惊讶的是,一点也不多。

我也很高兴看到我所怀疑的:在无正则表达式的情况下,使用反向xrange方法是不必要的,但它确实使代码看起来稍微好一点,代价是大约10%的性能。

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

from __future__ import with_statementfrom contextlib import contextmanagerimport 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_offsetsegments,_from_index,leftover = [],0,(period-start_digit) % 3for _index in xrange(start_digit+3 if not leftover else start_digit+leftover,period,3):segments.append(value[_from_index:_index])_from_index=_indexif not segments:return valuesegments.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=_indexif not segments:return valuesegments.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:breaksegments.append(value[digit_group.start():last_endoffset])last_endoffset=digit_group.start()if not segments:return valueif 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 newelse:return intcomma(new)
@contextmanagerdef timed(save_time_func):begin=time.time()try:yieldfinally: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):passfor 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 testtestset(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

以下是测试结果:

intcomma 5 5intcomma_noregex 5 5intcomma_noregex_reversed 5 5intcomma_recurs 5 5intcomma 567 567intcomma_noregex 567 567intcomma_noregex_reversed 567 567intcomma_recurs 567 567intcomma 1234 1,234intcomma_noregex 1234 1,234intcomma_noregex_reversed 1234 1,234intcomma_recurs 1234 1,234intcomma 1234.56 1,234.56intcomma_noregex 1234.56 1,234.56intcomma_noregex_reversed 1234.56 1,234.56intcomma_recurs 1234.56 1,234.56intcomma -253892.045 -253,892.045intcomma_noregex -253892.045 -253,892.045intcomma_noregex_reversed -253892.045 -253,892.045intcomma_recurs -253892.045 -253,892.0451 intcomma testset_xsimple 0.04100012779241 intcomma testset_simple 0.03699994087221 intcomma testset_onecomma 0.2130000591281 intcomma testset_complex 0.2960000038151 intcomma testset_average 0.5030000209811 intcomma_noregex testset_xsimple 0.1340000629431 intcomma_noregex testset_simple 0.1349999904631 intcomma_noregex testset_onecomma 0.1909999847411 intcomma_noregex testset_complex 0.2090001106261 intcomma_noregex testset_average 0.5130000114441 intcomma_noregex_reversed testset_xsimple 0.1240000724791 intcomma_noregex_reversed testset_simple 0.127000093461 intcomma_noregex_reversed testset_onecomma 0.2300000190731 intcomma_noregex_reversed testset_complex 0.2369999885561 intcomma_noregex_reversed testset_average 0.562999963761 intcomma_recurs testset_xsimple 0.3480000495911 intcomma_recurs testset_simple 0.346000194551 intcomma_recurs testset_onecomma 0.6251 intcomma_recurs testset_complex 0.7739999294281 intcomma_recurs testset_average 1.68900012971 overhead testset_xsimple 0.01799988746641 overhead testset_simple 0.01900005340581 overhead testset_onecomma 0.01900005340581 overhead testset_complex 0.01900005340581 overhead testset_average 0.03099989891052 intcomma testset_xsimple 0.03600001335142 intcomma testset_simple 0.03699994087222 intcomma testset_onecomma 0.2079999446872 intcomma testset_complex 0.3020000457762 intcomma testset_average 0.5230000019072 intcomma_noregex testset_xsimple 0.1399998664862 intcomma_noregex testset_simple 0.1410000324252 intcomma_noregex testset_onecomma 0.2039999961852 intcomma_noregex testset_complex 0.2009999752042 intcomma_noregex testset_average 0.5230000019072 intcomma_noregex_reversed testset_xsimple 0.1300001144412 intcomma_noregex_reversed testset_simple 0.1299998760222 intcomma_noregex_reversed testset_onecomma 0.2360000610352 intcomma_noregex_reversed testset_complex 0.2419998645782 intcomma_noregex_reversed testset_average 0.5829999446872 intcomma_recurs testset_xsimple 0.3510000705722 intcomma_recurs testset_simple 0.3529999256132 intcomma_recurs testset_onecomma 0.6489999294282 intcomma_recurs testset_complex 0.8080000877382 intcomma_recurs testset_average 1.819000005722 overhead testset_xsimple 0.01899981498722 overhead testset_simple 0.01899981498722 overhead testset_onecomma 0.01900005340582 overhead testset_complex 0.01799988746642 overhead testset_average 0.02999997138983 intcomma testset_xsimple 0.03600001335143 intcomma testset_simple 0.03600001335143 intcomma testset_onecomma 0.2100000381473 intcomma testset_complex 0.3059999942783 intcomma testset_average 0.4930000305183 intcomma_noregex testset_xsimple 0.1319999694823 intcomma_noregex testset_simple 0.1360001564033 intcomma_noregex testset_onecomma 0.1929998397833 intcomma_noregex testset_complex 0.2020001411443 intcomma_noregex testset_average 0.5099999904633 intcomma_noregex_reversed testset_xsimple 0.1259999275213 intcomma_noregex_reversed testset_simple 0.1269998550423 intcomma_noregex_reversed testset_onecomma 0.2359998226173 intcomma_noregex_reversed testset_complex 0.2430000305183 intcomma_noregex_reversed testset_average 0.562000036243 intcomma_recurs testset_xsimple 0.3370001316073 intcomma_recurs testset_simple 0.3420000076293 intcomma_recurs testset_onecomma 0.6099998950963 intcomma_recurs testset_complex 0.753 intcomma_recurs testset_average 1.683000087743 overhead testset_xsimple 0.01899981498723 overhead testset_simple 0.0180001258853 overhead testset_onecomma 0.0180001258853 overhead testset_complex 0.01799988746643 overhead testset_average 0.0299999713898

下面是一个单行的regex替换:

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

仅适用于inegral输出:

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

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

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

NB:对于超过三个十进制数字无法正常工作,因为它将尝试对十进制部分进行分组:

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

它是如何运作的

让我们把它分解:

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

这是另一个使用适用于整数的生成器函数的变体:

def ncomma(num):def _helper(num):# assert isinstance(numstr, basestring)numstr = '%d' % numfor 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)]))

这里有一个测试:

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

Python 2.5+和Python 3的一行(仅为正整型):

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

这个和逗号一起赚钱

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

您还可以使用'{:n}'.format( value )来表示语言环境。我认为这是语言环境解决方案的最简单方法。

有关详细信息,请在pythondoc中搜索thousands

对于货币,您可以使用locale.currency,设置标志grouping

代码

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

产出

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

我是一个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)

也可以使用列表理解:

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)

这更短,可能是一句话,但你必须做一些心理体操才能理解它为什么有效。在这两种情况下,我们得到:

for i in range(1, 11):instr = '1234567890'[:i]print(instr, add_commas(instr))
1 112 12123 1231234 1,23412345 12,345123456 123,4561234567 1,234,56712345678 12,345,678123456789 123,456,7891234567890 1,234,567,890

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

从Python 2.6版本开始,您可以这样做:

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

对于Python版本<2.6并且只是为了您的信息,这里有2个手动解决方案,它们将浮点数转换为整数,但负数正常工作:

def format_number_using_lists(number):string = '%d' % numberresult_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)

这里需要注意的几件事:

  • 这一行:string='%d'%号漂亮地将数字转换为字符串,它支持负数,并从浮点数中删除分数,使它们成为整数;
  • 此切片索引[::-3]返回从结束,所以我使用了另一个切片[1:]来删除最后一项因为我不需要最后一个数字后面的逗号;
  • 此条件如果l[索引] ! = '-'用于支持负数,请勿在减号后插入逗号。

还有一个更硬核的版本:

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

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

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

退货:4,385,893.38

更新:我最近遇到了这种格式的问题(无法告诉你确切的原因),但能够通过删除0来修复它:

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

python3

--

整数(不含小数):

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

--

浮点数(小数):

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

其中f之前的数字指定小数位数。

--

奖金

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

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

我很惊讶没有人提到你可以在Python 3.6+中使用f字符串做到这一点,就像这样简单:

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

…其中冒号后面的部分是格式说明符。逗号是您想要的分隔符,因此f"{num:_}"使用下划线而不是逗号。此方法只能使用“,”和“_”。

这相当于对旧版本的python 3使用format(num, ",")

当你第一次看到它时,这可能看起来像魔法,但事实并非如此。它只是语言的一部分,并且通常需要足够的快捷方式。要了解更多信息,请查看的组子组件

我有这个代码的python 2和python 3版本。我知道这个问题是针对python 2提出的,但现在(8年后lol)人们可能会使用python 3。

Python 3代码:

import randomnumber = str(random.randint(1, 10000000))comma_placement = 4print('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 + 4else:for i in range(0, len(number) // 3):number = number[0:len(number) - comma_placement + 1] + ',' + number[len(number) - comma_placement + 1:]breakprint('The new and improved number is: {}'.format(number))


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

import randomnumber = str(random.randint(1, 10000000))comma_placement = 4print '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 + 4else:for i in range(0, len(number) // 3):number = number[0:len(number) - comma_placement + 1] + ',' + number[len(number) - comma_placement + 1:]breakprint 'The new and improved number is: %s.' % (number)

稍微扩展一下Ian Schneider的回答:

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

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

示例

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

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

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

接受的答案是好的,但我实际上更喜欢format(number,',')。对我来说更容易解释和记忆。

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

意大利:

>>> import locale>>> locale.setlocale(locale.LC_ALL,"")'Italian_Italy.1252'>>> f"{1000:n}"'1.000'

这是每个PEP烘焙到python中->https://www.python.org/dev/peps/pep-0378/

只需使用格式(1000,', d')来显示带有千分隔符的整数

有更多的格式在PEP中描述,有它

通用解决方案

我在之前投票最多的答案中发现了点分隔符的一些问题。我设计了一个通用解决方案,您可以使用任何您想要的作为千分隔符,而无需修改语言环境。我知道这不是最优雅的解决方案,但它可以完成工作。随时改进它!

def format_integer(number, thousand_separator='.'):def reverse(string):string = "".join(reversed(string))return string
s = reverse(str(number))count = 0result = ''for char in s:count = count + 1if count % 3 == 0:if len(s) == count:result = char + resultelse:result = thousand_separator + char + resultelse:result = char + resultreturn result

print(format_integer(50))# 50print(format_integer(500))# 500print(format_integer(50000))# 50.000print(format_integer(50000000))# 50.000.000

python中的Babel模块具有根据提供的语言环境应用逗号的功能。

要安装Babel,请运行以下命令。

pip install babel

使用

format_currency(1234567.89, 'USD', locale='en_US')# Output: $1,234,567.89format_currency(1234567.89, 'USD', locale='es_CO')# Output: US$ 1.234.567,89 (raw output US$\xa01.234.567,89)format_currency(1234567.89, 'INR', locale='en_IN')# Output: ₹12,34,567.89

以下是一些使用格式化的方法(与浮点数和int兼容)

num = 2437.68
# Way 1: String Formatting
'{:,}'.format(num)>>> '2,437.68'

# Way 2: F-Strings
f'{num:,}'>>> '2,437.68'

# Way 3: Built-in Format Function
format(num, ',')>>> '2,437.68'

在浮点数中同时使用分隔符和小数:(在这个例子中,小数点后两位)

large_number = 4545454.26262666print(f"Formatted: {large_number:,.2f}")

结果:格式:4,545,454.26

最简单的答案:

format (123456, ",")

结果:

'123,456'