PEP 378 – 千位分隔符的格式说明符
- 作者:
- Raymond Hettinger <python at rcn.com>
- 状态:
- 最终
- 类型:
- 标准跟踪
- 创建:
- 2009年3月12日
- Python 版本:
- 2.7, 3.1
- 历史记录:
- 2009年3月12日
动机
提供一种简单、不依赖区域设置的方式来格式化带有千位分隔符的数字。
添加千位分隔符是使程序输出人性化最简单的方法之一,可以提高其专业外观和可读性。
在金融领域,带有千位分隔符的输出是标准做法。金融用户和非专业程序员发现区域设置方法令人沮丧、晦涩且不明显。
locale 模块提出了另外两个挑战。首先,它是一个全局设置,不适用于需要以多种区域设置提供服务的多分支应用程序。其次,相关区域设置的名称(例如“de_DE”)可能因平台而异,或者根本未定义。locale 模块的文档详细描述了这些以及许多其他挑战。
目标不是替换 locale 模块、执行国际化任务或适应所有可能的约定。此类任务更适合于像Babel这样的强大工具。相反,目标是简化许多用户的常见日常任务。
主要提案(来自 Alyssa Coghlan,最初称为提案 I)
逗号将被添加到 format() 说明符迷你语言中
[[fill]align][sign][#][0][width][,][.precision][type]
“,”选项表示输出中应包含逗号作为千位分隔符。与不使用句点作为小数点的区域设置一样,使用不同数字分隔约定规则的区域设置需要使用 locale 模块来获取适当的格式。
该提案适用于浮点数、整数和小数。它还允许轻松替换其他分隔符。例如
format(n, "6,d").replace(",", "_")
此技术完全通用,但在需要交换逗号和小数点的一种情况下很笨拙
format(n, "6,f").replace(",", "X").replace(".", ",").replace("X", ".")
width 参数表示包括逗号和小数点在内的总长度
format(1234, "08,d") --> '0001,234'
format(1234.5, "08,.1f") --> '01,234.5'
“,”选项如上所述,适用于类型“d”、“e”、“f”、“g”、“E”、“G”、“%”、“F”和“”。为了允许将来扩展,它对于其他类型(二进制、八进制、十六进制、字符等)未定义。
该提案的优点是比替代提案更简单,但灵活性要差得多,并且在开箱即用时满足的用户需求更少。预计会出现一些其他解决方案来指定替代分隔符。
迷你语言的当前版本
- Python 2.6 文档
- PEP 3101 高级字符串格式化
其他语言的研究
扫描网络后,我发现千位分隔符通常是逗号、点、空格、撇号或下划线之一。
C-Sharp 提供两种样式(图像格式和类型说明符)。类型说明符方法是区域设置感知的。图像格式仅提供逗号作为千位分隔符
String.Format("{0:n}", 12400) ==> "12,400"
String.Format("{0:0,0}", 12400) ==> "12,400"
Common Lisp 在~D
十进制类型说明符之前使用冒号来输出逗号作为千位分隔符。~D
的一般形式是~mincol,padchar,commachar,commaintervalD
。padchar 默认为空格。commachar 默认为逗号。commainterval 默认为 3。
(format nil "~:D" 229345007) => "229,345,007"
- ADA 语言 允许在其数字文字中使用下划线。
Visual Basic 及其同类产品(如MS Excel)使用完全不同的样式,并具有超灵活的自定义格式说明符,例如
"_($* #,##0_)".
COBOL 使用类似于以下的图片子句:
PICTURE $***,**9.99CR
Java 提供了一个Decimal.Format 类,该类使用图像模式(一个用于正数,一个可选的用于负数),例如:"#,##0.00;(#,##0.00)"
。它允许任意分组,包括数百和万,以及不均匀的分组。特殊模式字符是非本地化的(使用点作为小数分隔符,使用逗号作为分组分隔符)。用户可以使用格式化程序的DecimalFormatSymbols 对象提供另一组符号。
替代提案(来自 Eric Smith,最初称为提案 II)
使千位分隔符和小数分隔符都可由用户指定,但不要依赖区域设置。为简单起见,将选择限制为逗号、点、空格、撇号或下划线。空格可以是 U+0020 或 U+00A0。
只要分隔符后面跟着精度,它就是小数分隔符,并且前面的可选分隔符是千位分隔符。当精度不存在时,单个说明符表示千位分隔符
[[fill]align][sign][#][0][width][tsep][dsep precision][type]
示例
format(1234, "8.1f") --> ' 1234.0'
format(1234, "8,1f") --> ' 1234,0'
format(1234, "8.,1f") --> ' 1.234,0'
format(1234, "8 ,f") --> ' 1 234,0'
format(1234, "8d") --> ' 1234'
format(1234, "8,d") --> ' 1,234'
format(1234, "8_d") --> ' 1_234'
该提案满足大多数需求,但以需要付出更多努力进行解析为代价。并非所有可能的约定都涵盖在内,但至少有一个选项(空格或下划线)应该易于阅读、理解,并且对来自不同背景的人们有用。
如示例所示,width 参数表示包括千位分隔符和小数分隔符在内的总长度。
未针对 locale 模块提出任何更改。
千位分隔符如上所述,适用于类型“d”、“e”、“f”、“g”、“%”、“E”、“G”和“F”。为了允许将来扩展,它对于其他类型(二进制、八进制、十六进制、字符等)未定义。
此替代提案的缺点是难以在心理上解析单个分隔符是千位分隔符还是小数分隔符。也许将小数分隔符与精度说明符关联起来过于晦涩。
评论
- 一些评论者根本不喜欢格式字符串的想法,并认为它们难以阅读。建议的替代方案包括 COBOL 样式的 PICTURE 方法或一个使用关键字参数的便捷函数,用于所有可能的组合。
- 一些新闻组回复者认为,没有地方适合任何未经国际化的脚本,并且提供一种简单的方法来硬编码特定选择(从而减少使用区域设置感知方法的动机)是倒退了一步。
- 另一个想法是,将某些特定约定嵌入到各个格式字符串中,使得以后难以更改该约定。没有提出可行的替代方案,但总体思路是只设置一次约定并使其在所有地方都适用(其他人评论说 locale 已经提供了一种执行此操作的方法)。
- 在浮点数的小数部分对数字进行分组有一些先例,但此 PEP 并未涉足该领域。仅对小数点左边的数字进行分组。这并不排除将来扩展;它只是专注于对格式化语言的一个普遍有用的扩展。
- James Knight 观察到,印度/巴基斯坦数字系统以百位为单位进行分组。Ben Finney 指出,中国人以万位为单位进行分组。Eric Smith 指出,这些已经由 locale 模块中的“n”说明符处理(尽管仅限于整数)。此 PEP 不会尝试支持所有这些可能性。它专注于一个相对常见的组合约定,该约定提供了一种快速的方法来提高许多(尽管不是全部)上下文中的可读性。
版权
本文档已进入公有领域。
来源:https://github.com/python/peps/blob/main/peps/pep-0378.rst