Python 使用.format()语法的区域设置感知字符串格式

Python 使用.format()语法的区域设置感知字符串格式,python,locale,string-formatting,Python,Locale,String Formatting,是否有一种(常规)方法可以使用.format(){:}语法在Python中进行区域设置感知字符串格式化?我知道locale.format_string(),但这只接受旧的%语法{:n}存在,但仅作为{:d}的替换,不适用于其他格式 我目前的方法如下所示,我预计在大多数非琐碎的情况下都会失败 import locale import string class LocaleFormatter(string.Formatter): def format_field(self, value,

是否有一种(常规)方法可以使用
.format()
{:}
语法在Python中进行区域设置感知字符串格式化?我知道
locale.format_string()
,但这只接受旧的
%
语法<代码>{:n}存在,但仅作为
{:d}
的替换,不适用于其他格式

我目前的方法如下所示,我预计在大多数非琐碎的情况下都会失败

import locale
import string


class LocaleFormatter(string.Formatter):
    def format_field(self, value, format_spec):
        if format_spec[-1] not in 'eEfFgGdiouxXcrs':  # types copied from locale._percent_re
            return super().format_field(value, format_spec)
        grouping = ',' in format_spec or '_' in format_spec
        format_spec = '%' + format_spec.replace(',', '').replace('_', '')
        return locale.format_string(format_spec, value, grouping)


locale.setlocale(locale.LC_ALL, '')
fmt = LocaleFormatter()
fmt.format("Length: {:,.2f} mm, width: {:,.2f} mm", 1234.56, 7890)  # expected format is 1.234,56 for most locales

您可以实现将浮点转换为十进制、设置精度以及手动添加前导空格(如果需要)所需的功能:

import decimal
import locale
import re
import string

class LocaleFormatter(string.Formatter):
    def format_field(self, value, format_spec):
        if format_spec[-1] not in 'eEfFgGdiouxXcrs':  # types copied from locale._percent_re
            return super().format_field(value, format_spec)
        grouping = ',' in format_spec or '_' in format_spec
        prec_re = re.match(r',?(?P<spec>(?P<width>\d+)?(.(?P<precision>\d+))?)?[eEfFgGdiouxXcrs]', format_spec)
        if prec_re is not None and prec_re.group('spec') is not None:
            space_len = prec_re.group('width')
            after_dot = prec_re.group('precision')
            if after_dot is not None:
                pre_dot_value_len = len(str(int(value)))
                ctx = decimal.Context(prec=int(after_dot) + pre_dot_value_len)
                # prec turned out to be the length of the decimal repr, not precision
                value = ctx.create_decimal(value)
            if space_len is not None:
                after_dot = 0 if after_dot is None else int(after_dot)
                pre_dot = len(str(value))
                how_many = pre_dot - after_dot - 1  # -1 for the dot character
                if how_many > 0:
                    format_spec = how_many * ' ' + format_spec
        format_spec = '%' + format_spec.replace(',', '').replace('_', '')
        return locale.format_string(format_spec, value, grouping)

locale.setlocale(locale.LC_ALL, 'DE-DE')
fmt = LocaleFormatter()
res = fmt.format("Length: {:,.2f} mm, width: {:,2f} mm", 1234.567878, 7890)  # expected format is 1.234,56 for most locales
print(res)

请注意,格式化后建议的正确值未正确舍入。上面的一个问题是。

我的问题是关于使用现有的字符串格式语法的,所以我不认为必须使用Babel自己的格式语言是正确的答案。然后我就可以使用
locale.format\u string()
。我还认为Babel不接受一般字符串,只接受数字(即相当于
“长度:{:,.2f}mm,宽度:{:,.2f}mm”。格式(1234.567890)
)。我在问题中把这一点说得更清楚了。@BrtH:请看,我现在修改了它,以便更好地回答您的问题。
Length: 1.234,57 mm, width:         7.890,000000 mm