12

我有一本字典,键中有一个冒号,我想打印。不幸的是,冒号字符用于格式化,所以我需要以某种方式对其进行转义。

例如:

>>> d = {'hello': 'world', 'with:colon': 'moo'}

>>> '{hello}'.format(**d)
'world'

>>> '{with:colon}'.format(**d)
KeyError: 'with'

>>> '{with\:colon}'.format(**d)
KeyError: 'with\\'

>>> '{with::colon}'.format(**d)
KeyError: 'with'
4

6 回答 6

10

根据文档,您所要求的根本不可能。具体来说,

因为 arg_name 不是用引号分隔的,所以不可能在格式字符串中指定任意字典键(例如,字符串'10'或)。':-]'

于 2013-11-11T18:47:27.420 回答
6

作为一种解决方法:

>>> d = {'hello': 'world', 'with:colon': 'moo'}
>>> '{hello} {}'.format(d['with:colon'],**d)
'world moo'
>>> '{hello} {0}'.format(d['with:colon'],**d)
'world moo'
于 2013-11-11T18:56:37.863 回答
2

你不能 - 键必须在语法上等同于 Python 标识符。请参阅文档中的格式化字符串语法

replacement_field ::=  "{" [field_name] ["!" conversion] [":" format_spec] "}"
field_name        ::=  arg_name ("." attribute_name | "[" element_index "]")*
arg_name          ::=  [identifier | integer]
attribute_name    ::=  identifier
于 2013-11-11T18:47:50.020 回答
2

从 python 3.6 开始,您可以使用新的 f 字符串格式来解决这个问题:

>>> d = {'hello': 'world', 'with:colon': 'moo'}
>>> print(f"with:colon is equal to {d['with:colon']}")
with:colon is equal to moo
于 2018-02-14T09:10:11.010 回答
1

正如@murgatroid99在他的回答中指出的那样,这是不可能的。

一种解决方法是将密钥替换为有效的密钥:

d_sanitised = {key.replace(":", "-"): value for key, value in d.items()}

当然,如果可能与其他键发生冲突,您可能需要小心。

>>> d = {'hello': 'world', 'with:colon': 'moo'}
>>> d_sanitised = {key.replace(":", "-"): value for key, value in d.items()}
>>> '{with-colon}'.format(**d_sanitised)
'moo'

显然,这假设您可以修改格式字符串以适应。理想情况下,只需修改两端以避免冒号。

于 2013-11-11T18:50:44.187 回答
1

遗憾的是内置格式化程序不允许这样做。一个明显的语法扩展是允许在必要时引用键。您的格式字符串将是这样的:

format('{"with:colon"} and {hello}'

幸运的是,扩展 Formatter 以提供这种语法似乎很容易,这是一个 POC 实现:

class QuotableFormatter(string.Formatter):
    def __init__(self):
        self.super = super(QuotableFormatter, self)
        self.super.__init__()
        self.quotes = {}

    def parse(self, format_string):
        fs = ''
        for p in re.findall(r'(?:".+?")|(?:[^"]+)', format_string):
            if p[0] == '"':
                key = '_q_' + str(len(self.quotes))
                self.quotes[key] = p[1:-1]
                fs += key
            else:
                fs += p
        return self.super.parse(fs)

    def get_field(self, field_name, args, kwargs):
        if field_name.startswith('_q_'):
            field_name = self.quotes[field_name]
        return self.super.get_field(field_name, args, kwargs)

用法:

d = {'hello': 'world', 'with:colon': 'moo', "weird!r:~^20": 'hi'}
print QuotableFormatter().format('{"with:colon":*>20} and {hello} and {"weird!r:~^20"}', **d)
# *****************moo and world and hi
于 2013-11-11T21:39:07.383 回答