只是子类 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
P.P.S.如果你不能 locale 工作,我'd suggest a modified version of Mark'的回答:
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)
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
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
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
>>> 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('-,','-')
265
我确定必须有一个标准的库函数,但尝试用递归自己编写它很有趣所以这就是我想出的:
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)
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
1
您还可以使用 '{:n}'.format( value ) 作为区域设置表示 . 我认为这是区域设置解决方案最简单的方法 .
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'
s = str(1234567)
print ','.join([s[::-1][k:k+3][::-1] for k in xrange(len(s)-1, -1, -3)])
这仅适用于非负整数 .
5
这是使用发电机的另一种变体适用于整数的函数:
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)]))
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))
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)
这里有几点需要注意:
这一行: string = '%d' % number 精美地将数字转换为字符串,它支持负数并从浮点数中删除分数,使它们成为整数;
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)
-1
Python 2.5和Python 3的一个衬垫(仅限正int):
''.join(reversed([x + (',' if i and not i % 3 else '') for i, x in enumerate(reversed(str(1234567)))]))
4
意大利数字:千位分隔符是' . '
我这样解决了......对于一个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)
出:le immobilizzazioni valgono 419.168€ . 我debiti每TFR sono pari 13.255€ . l'attivocircolanteèdi195.443欧元 . il fondo rischi ed oneri ha un importo pari 13.374欧元 . 我debiti sono 180.947€ . 我的评级为2.271欧元 . 我评价一个1.864欧元的risconti passivi sono pari . 我相信我的社会声音为17.630欧元 .
1400
我很惊讶没有人提到你可以用Python 3.6中的f字符串做到这一点就像这样简单:
>>> num = 10000000
>>> print(f"{num:,d}")
10,000,000
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代码:(编辑.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)
26 回答
只是子类
long
(或float
,或其他) . 这是非常实用的,因为这样你仍然可以在数学运算中使用你的数字(因此也就是现有的代码),但它们都会在你的终端中很好地打印出来 .我得到了这个工作:
当然,您不需要国际化支持,但它清晰,简洁,并使用内置库 .
附: “%d”是通常的%式格式化程序 . 您可以只有一个格式化程序,但它可以是字段宽度和精度设置方面的任何需要 .
P.P.S.如果你不能
locale
工作,我'd suggest a modified version of Mark'的回答:递归对于负面情况很有用,但每个逗号的一次递归对我来说似乎有些过分 .
Python 3
Integers (without decimal):
"{:,d}".format(1234567)
Floats (with decimal):
"{:,.2f}".format(1234567)
其中
f
之前的数字指定小数位数 .Bonus
印度lakhs / crores编号系统(12,34,567)的快速启动功能:
https://stackoverflow.com/a/44832241/4928578
接受的答案很好,但我其实更喜欢
format(number,',')
. 我更容易理解和记忆 .https://docs.python.org/3/library/functions.html#format
这里也适用于花车:
用法示例:
我正在使用python 2.5,因此我无法访问内置格式 .
我查看了Django代码intcomma(下面的代码中的intcomma_recurs),并意识到它效率低下,因为它是递归的,并且每次运行时编译正则表达式也不是一件好事 . 这不是一个“问题”,因为django并不真正专注于这种低级别的表现 . 此外,我预计性能会有10倍的差异,但速度只有3倍 .
出于好奇,我实现了几个版本的intcomma,以了解使用正则表达式时的性能优势 . 我的测试数据总结了这个任务的一个小优势,但令人惊讶的是没有多少 .
我也很高兴看到我所怀疑的:在无正则表达式的情况下使用反向xrange方法是不必要的,但它确实使代码看起来稍微好一些,但代价是~10% .
另外,我假设你传入的是一个字符串,看起来有点像数字 . 结果不确定 .
以下是测试结果:
从comments到activestate配方498181我重写了这个:
它使用正则表达式功能:lookahead,即
(?=\d)
,以确保只有三位数字的组有一个数字'after'它们得到一个逗号 . 我说'after'因为此时字符串是反向的 .[::-1]
只是反转一个字符串 .对于花车:
对于整数:
由于效率低下和不可读性,很难被击败:
我确定必须有一个标准的库函数,但尝试用递归自己编写它很有趣所以这就是我想出的:
话虽如此,如果其他人确实找到了标准的方法,你应该使用它 .
对于Python≥2.7:
按Format Specification Mini-Language,
这是一个单行正则表达式替换:
仅适用于非常规输出:
或者对于少于4位数的浮点数,请将格式说明符更改为
%.3f
:NB: 超过三位小数后无法正常工作,因为它会尝试对小数部分进行分组:
它是如何工作的
让我们分解一下:
您还可以使用
'{:n}'.format( value )
作为区域设置表示 . 我认为这是区域设置解决方案最简单的方法 .有关更多信息,请在Python DOC中搜索
thousands
.对于货币,您可以使用
locale.currency
,设置标志grouping
:Code
Output
这是删除不相关的部分并清理一下后的区域设置分组代码:
(以下仅适用于整数)
这里已经有了一些很好的答案 . 我只想添加它以供将来参考 . 在python 2.7中,将有一个千位分隔符的格式说明符 . 根据python docs,它的工作原理如下
在python3.1中你可以做同样的事情:
如果您不想依赖任何外部库:
这仅适用于非负整数 .
这是使用发电机的另一种变体适用于整数的函数:
这是一个测试:
我是一名Python初学者,但是一位经验丰富的程序员 . 我有Python 3.5,所以我可以使用逗号,但这仍然是一个有趣的编程练习 . 考虑无符号整数的情况 . 用于添加数千个分隔符的最易读的Python程序似乎是:
也可以使用列表理解:
这个更短,可能是一个班轮,但你必须做一些心理体操,以了解它的工作原理 . 在这两种情况下我们得到:
如果你想要理解程序,第一个版本是更明智的选择 .
我更喜欢基于语言环境的实际项目解决方案,但我认为应该在这里提到使用切片分配的方法:
doctests的要点在这里 - https://gist.github.com/ei-grad/b290dc761ae253af69438bbb94d82683
这与钱一起做钱
这就是我为花车做的事情 . 虽然,老实说,我不确定它适用于哪个版本 - 我使用的是2.7:
返回:4,385,893.38
更新:我最近遇到了这种格式的问题(无法告诉您具体原因),但是能够通过删除
0
来修复它:从Python 2.6版开始,你可以这样做:
对于Python版本<2.6并且只是为了您的信息,这里有2个手动解决方案,它们将浮点数转换为整数但负数字正常工作:
这里有几点需要注意:
这一行: string = '%d' % number 精美地将数字转换为字符串,它支持负数并从浮点数中删除分数,使它们成为整数;
这个切片 indexes[::-3] 从结尾开始返回每个第三个项目,所以我使用了另一个切片 [1:] 来删除最后一个项目因为我在最后一个数字后面不需要逗号;
此条件 if l[index] != '-' 用于支持负数,请勿在减号后插入逗号 .
还有一个更硬核的版本:
Python 2.5和Python 3的一个衬垫(仅限正int):
意大利数字:千位分隔符是' . '
我这样解决了......对于一个dictonary
出:le immobilizzazioni valgono 419.168€ . 我debiti每TFR sono pari 13.255€ . l'attivocircolanteèdi195.443欧元 . il fondo rischi ed oneri ha un importo pari 13.374欧元 . 我debiti sono 180.947€ . 我的评级为2.271欧元 . 我评价一个1.864欧元的risconti passivi sono pari . 我相信我的社会声音为17.630欧元 .
我很惊讶没有人提到你可以用Python 3.6中的f字符串做到这一点就像这样简单:
...冒号后面的部分是格式说明符 . 逗号是您想要的分隔符,因此
f"{num:_d}"
使用下划线而不是逗号 .这相当于使用旧版本的python 3
format(num, ",d")
.略微扩大Ian Schneider的答案:
如果要使用自定义千位分隔符,最简单的解决方案是:
例子
如果你想要像这样的德语表示,它会变得有点复杂:
我有一个python 2和python 3版本的代码 . 我知道问题是python 2,但现在(8年后lol)人们可能会使用python 3 .
Python 3代码:
Python 2代码:(编辑.python 2代码不起作用 . 我认为语法不同) .