Python - 也适用于小数的千位分隔符,保留 4 位有效数字
Python - Thousands separator that also works for decimals, keeping 4 significant digits
我正在使用 API 来获取有关加密货币的数据 (https://api.coinmarketcap.com/v1/ticker/?convert=USD),正如你们中的一些人可能知道的那样,加密货币的价值可能超过 4000 美元 (BTC) 或低于 0.000001 美元其他。我必须工作并轻松比较所有这些数字。
在加拿大,我们使用 space 字符作为千位分隔符。我希望它能为数千人工作,但也能对小数位进行分组。另外,我需要一种方法来只保留一些 significant 数字。例如,对于比特币,我不需要小数部分。我想总是至少有 4 有效数字,这基本上意味着,如果 number >= 1000
,我不需要小数部分(但我保留完整的整数部分),如果它是 < 0
,我希望在第一个非零数字之后至少有 3 个附加数字(必要时四舍五入)。
我想要的输入 => 输出示例:
65410845186.1 => 65 410 845 186
43245.1 => 43 245
285.1234 => 285.1
0.01234567 => 0.123 5
0.001234054 => 0.001 234
0.001034538 => 0.001 035
0.00010001 => 0.000 100 0
1 => 1.000
1.0006 => 1.001
脚本需要在不同的操作系统上运行。我不认为任何 locale
或微不足道的 format
实现都可以在这里工作。什么是双向添加 space 分隔符的最佳方法,使用点作为小数点分隔符,同时保留 4 个有效数字(必要时四舍五入)除了数字 >= 1000
我只保留整数部分?
我从我在 Whosebug 上找到的另一段代码中得到了 space 分隔符作为千位分隔符:
def splitThousands(s, tSep=' ', dSep=','):
if s.rfind('.')>0:
rhs=s[s.rfind('.')+1:]
s=s[:s.rfind('.')]
if len(s) <= 3: return s + dSep + rhs
return splitThousands(s[:-3], tSep) + tSep + s[-3:] + dSep + rhs
else:
if len(s) <= 3: return s
return splitThousands(s[:-3], tSep) + tSep + s[-3:]
但是它没有考虑有效位数,也没有为小数部分添加分隔符。
注意:这些值波动很多,我确实不真的介意浮点值[=18]的极端极端情况=] 将四舍五入为 1.001
.
不完全是一个干净或直接的解决方案,但这里有一个符合要求的函数:
from math import floor, log10
def format_btc(value, tSep=' ', dSep='.', precision=4, grouping=3):
int_digits = max(int(floor(log10(value))) + 1, 0)
if int_digits >= precision:
int_part = int(round(value))
decimal_part = None
else:
int_part = int(floor(value))
decimal_part = value % 1.0
int_str = str(int_part)[::-1]
int_str = [int_str[i:i + grouping][::-1]
for i in range(0, len(int_str), grouping)]
int_str = tSep.join(reversed(int_str))
if decimal_part is None:
return int_str
if int_digits > 0:
num_decimals = precision - int_digits
else:
decimal_str = "{:.{precision}e}".format(decimal_part, precision=precision - 1)
decimal_pos = -int(decimal_str.split("e")[1])
num_decimals = decimal_pos + precision - 1
decimal_str = "{:.{precision}f}".format(decimal_part, precision=num_decimals)
decimal_str = decimal_str.split(".")[1]
if int_digits > 0:
decimal_str = decimal_str[:precision - int_digits]
decimal_str = [decimal_str[i:i + grouping] for i in range(0, len(decimal_str), grouping)]
decimal_str = tSep.join(decimal_str)
return dSep.join((int_str, decimal_str))
tests = [65410845186.123456, 4324.1, 285.1234, 0.01234567, 0.001234054,
0.001034538, 0.00010001, 1390390000.0, 1.0006]
for test in tests:
print("{:<20f} => {:s}".format(test, format_btc(test)))
输出:
65410845186.123459 => 65 410 845 186
4324.100000 => 4 324
285.123400 => 285.1
0.012346 => 0.012 35
0.001234 => 0.001 234
0.001035 => 0.001 035
0.000100 => 0.000 100 0
1390390000.000000 => 1 390 390 000
1.000600 => 1.001
我正在使用 API 来获取有关加密货币的数据 (https://api.coinmarketcap.com/v1/ticker/?convert=USD),正如你们中的一些人可能知道的那样,加密货币的价值可能超过 4000 美元 (BTC) 或低于 0.000001 美元其他。我必须工作并轻松比较所有这些数字。
在加拿大,我们使用 space 字符作为千位分隔符。我希望它能为数千人工作,但也能对小数位进行分组。另外,我需要一种方法来只保留一些 significant 数字。例如,对于比特币,我不需要小数部分。我想总是至少有 4 有效数字,这基本上意味着,如果 number >= 1000
,我不需要小数部分(但我保留完整的整数部分),如果它是 < 0
,我希望在第一个非零数字之后至少有 3 个附加数字(必要时四舍五入)。
我想要的输入 => 输出示例:
65410845186.1 => 65 410 845 186
43245.1 => 43 245
285.1234 => 285.1
0.01234567 => 0.123 5
0.001234054 => 0.001 234
0.001034538 => 0.001 035
0.00010001 => 0.000 100 0
1 => 1.000
1.0006 => 1.001
脚本需要在不同的操作系统上运行。我不认为任何 locale
或微不足道的 format
实现都可以在这里工作。什么是双向添加 space 分隔符的最佳方法,使用点作为小数点分隔符,同时保留 4 个有效数字(必要时四舍五入)除了数字 >= 1000
我只保留整数部分?
我从我在 Whosebug 上找到的另一段代码中得到了 space 分隔符作为千位分隔符:
def splitThousands(s, tSep=' ', dSep=','):
if s.rfind('.')>0:
rhs=s[s.rfind('.')+1:]
s=s[:s.rfind('.')]
if len(s) <= 3: return s + dSep + rhs
return splitThousands(s[:-3], tSep) + tSep + s[-3:] + dSep + rhs
else:
if len(s) <= 3: return s
return splitThousands(s[:-3], tSep) + tSep + s[-3:]
但是它没有考虑有效位数,也没有为小数部分添加分隔符。
注意:这些值波动很多,我确实不真的介意浮点值[=18]的极端极端情况=] 将四舍五入为 1.001
.
不完全是一个干净或直接的解决方案,但这里有一个符合要求的函数:
from math import floor, log10
def format_btc(value, tSep=' ', dSep='.', precision=4, grouping=3):
int_digits = max(int(floor(log10(value))) + 1, 0)
if int_digits >= precision:
int_part = int(round(value))
decimal_part = None
else:
int_part = int(floor(value))
decimal_part = value % 1.0
int_str = str(int_part)[::-1]
int_str = [int_str[i:i + grouping][::-1]
for i in range(0, len(int_str), grouping)]
int_str = tSep.join(reversed(int_str))
if decimal_part is None:
return int_str
if int_digits > 0:
num_decimals = precision - int_digits
else:
decimal_str = "{:.{precision}e}".format(decimal_part, precision=precision - 1)
decimal_pos = -int(decimal_str.split("e")[1])
num_decimals = decimal_pos + precision - 1
decimal_str = "{:.{precision}f}".format(decimal_part, precision=num_decimals)
decimal_str = decimal_str.split(".")[1]
if int_digits > 0:
decimal_str = decimal_str[:precision - int_digits]
decimal_str = [decimal_str[i:i + grouping] for i in range(0, len(decimal_str), grouping)]
decimal_str = tSep.join(decimal_str)
return dSep.join((int_str, decimal_str))
tests = [65410845186.123456, 4324.1, 285.1234, 0.01234567, 0.001234054,
0.001034538, 0.00010001, 1390390000.0, 1.0006]
for test in tests:
print("{:<20f} => {:s}".format(test, format_btc(test)))
输出:
65410845186.123459 => 65 410 845 186
4324.100000 => 4 324
285.123400 => 285.1
0.012346 => 0.012 35
0.001234 => 0.001 234
0.001035 => 0.001 035
0.000100 => 0.000 100 0
1390390000.000000 => 1 390 390 000
1.000600 => 1.001