Python - 千位分隔符,也适用于小数,保留4位有效数字

时间:2017-09-20 09:30:36

标签: python python-3.x number-formatting

我使用API​​来获取有关加密货币的数据(https://api.coinmarketcap.com/v1/ticker/?convert=USD),正如您可能知道的那样,加密货币价值超过4000美元(BTC)或低于0.000001美元。我必须工作并轻松比较所有这些数字。

在加拿大,我们使用空格字符作为千元&#39;分隔器。我希望它可以为数千个工作,但也可以对小数位进行分组。此外,我需要一种方法来只保留一些重要的数字。比如比特币,我不想要小数部分。我希望始终至少有 4 有效数字,这基本上意味着,如果number >= 1000,我不需要小数部分(但我保持完整整数部分),如果是< 0,我希望在第一个非零数字后至少增加3位数(如有必要,可以进行舍入)。

输入的例子=&gt;输出我喜欢:

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实施都不适用于此。使用点作为小数分隔符的两种方式添加空格分隔符的最佳方法是什么,同时保留4位有效数字(必要时进行舍入)除了数字>= 1000,其中我只保留整数部分?< / p>

我让空间分隔符工作成千上万。我在StackOverflow上找到的另一段代码中的分隔符:

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

但它没有考虑有效数字的数量,也没有为小数部分添加分隔符。

注意:这些值波动很多,我真的介意极端极端情况,其中1.0004999999999的浮点值将四舍五入为{{ 1}}。

1 个答案:

答案 0 :(得分:1)

这不是一个干净或简单的解决方案,但这里有一个适合账单的功能:

NaN

输出:

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