如何在输出浮点数时添加千位分隔符?

27

我该如何格式化十进制数字,使得 32757121.33 显示为 32.757.121,33


11
在德国,原始海报的格式是正常的。 - Jonas Schäfer
5个回答

27

使用locale.format()

>>> import locale
>>> locale.setlocale(locale.LC_ALL, 'German')
'German_Germany.1252'
>>> print(locale.format('%.2f', 32757121.33, True))
32.757.121,33

你可以将区域设置限制在数字值的显示上(使用locale.format()locale.str()等),而不影响其他区域设置:

>>> locale.setlocale(locale.LC_NUMERIC, 'English')
'English_United States.1252'
>>> print(locale.format('%.2f', 32757121.33, True))
32,757,121.33
>>> locale.setlocale(locale.LC_NUMERIC, 'German')
'German_Germany.1252'
>>> print(locale.format('%.2f', 32757121.33, True))
32.757.121,33

2
这些调用还要考虑操作系统可用的区域设置,这会增加额外的麻烦。此外,不同的操作系统甚至不同的Linux发行版可能会有不同的区域设置名称(这意味着您必须在生产服务器上进行测试,或编写代码提供回退直到找到现有的区域设置)。 - jsbueno
1
@jsbueno:好观点。文档还指出,setlocale()不是线程安全的,并且在使用较大的多模块程序时存在其他几个问题,因此阅读文档非常重要。在小型程序中,这可能并不那么重要。此外,还有其他语言环境名称,如en_ENde_DE,可能比German等更通用;尽管我还没有找到允许的语言环境设置列表。 - Tim Pietzcker
我有一个编程问题,错误信息为:“Caught Error while rendering: unsupported locale setting”。我尝试了不同的变量(如German、german、de_DE等),但仍然无法解决。是否可以不使用locale,只使用format来解决这个问题? - yital9
你在哪个平台上运行程序? - Tim Pietzcker
1
问题在于它不是线程安全的,并且假定开发人员希望在程序中的任何地方都获得相同的效果(除非不断切换,这很糟糕和令人讨厌)。应该有一种方法可以在不必设置整个运行时平台的语言环境的情况下获取以给定语言环境格式化的值。例如,locale.format(format_string, value, locale) - 然而,貌似并没有这样的方法。 - Teekin

22

我找到了另一个解决方案:

'{:,.2f}'.format(num).replace(".","%").replace(",",".").replace("%",",")

4
可怕的解决方案。如果这个方法被用在数以千计长度各异的字符串上会怎样? - Daniel
5
没有(num)之后的那些废话也能让这个东西运行。 - Brian Leach
优美的解决方案,让编译器去完成它们的工作 :) - Alesis Joan
1
是的,现在看起来很糟糕,但我微笑着看着它。但是在2012年它还是有效的 :D - yital9

9

如果由于某些原因您不能或不想使用 locale,您也可以使用正则表达式来实现:

import re
def sep(s, thou=",", dec="."):
    integer, decimal = s.split(".")
    integer = re.sub(r"\B(?=(?:\d{3})+$)", thou, integer)
    return integer + dec + decimal

sep()函数接收一个标准Python浮点数的字符串表示,并将其返回为具有自定义千分位和小数分隔符的字符串。

>>> s = "%.2f" % 32757121.33
>>> sep(s)
'32,757,121.33'
>>> sep(s, thou=".", dec=",")
'32.757.121,33'

Explanation:
解释:
\B      # Assert that we're not at the start of the number
(?=     # Match at a position where it's possible to match...
 (?:    #  the following regex:
  \d{3} #   3 digits
 )+     #  repeated at least once
 $      #  until the end of the string
)       # (thereby ensuring a number of digits divisible by 3

1
非常感谢!如果您有兴趣,我还发现了这个变体'{:20,.2f}'.format(num).replace(".","%").replace(",",".").replace("%",",")。 - yital9
1
为什么要创建解释部分,当你可以使用 verbose 呢? - Daniel

0
>>> import locale

>>> locale.setlocale(locale.LC_ALL, 'en_GB.UTF-8')
'en_GB.UTF-8'
>>> print(locale.format_string('%.2f', 12742126.15, True))
12,742,126.15

这个示例代码适用于在docker容器中的GB。

FROM python:3.8.2-slim-buster

RUN apt-get update && apt-get install -y locales && \
    sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen && \
    dpkg-reconfigure --frontend=noninteractive locales

ENV LANG en_GB.UTF-8
ENV LC_ALL en_GB.UTF-8

你可以在终端(Linux发行版)上运行以下命令来查找区域设置:

locale -a

然后会出现完整的区域设置列表:

en_AG.utf8
en_AU.utf8
...
en_GB.utf8
...

0

我喜欢def sep...,但它并没有自动找到数字本地格式的问题。如果您不想在报告中添加大量代码,那么这确实是您想要的。

您可以使用g.periodsOrCommas={'thou':'.','dec':','},其中g是全局可用区域。

将sep更改为:

def sep(s:str):
    thou=g.periodsOrCommas['thou']
    dec= g.periodsOrCommas['dec'] 

然后作为程序设置的一部分,或者向用户进行查询,将句点和逗号设置为所需格式。在所有报告或窗口中,调用sep来处理浮点表示。 最后,您可以在sep中设置选项以指定小数位数,甚至是所需的格式类型。但这远远超出了当前问题的范围。 感谢您提供了一个解决我面临的实际问题的好方法。


这并不是问题的答案。一旦您有足够的声望,您将能够在任何帖子上发表评论;相反,提供不需要向询问者澄清的答案。- 来自审核 - Neizvestnyj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接