How do I escape a colon in Python format() when using kwargs?

拜拜、爱过 提交于 2019-12-23 07:15:39

问题


I have a dictionary with a colon in a key that I wish to print. Unfortunately the colon character is used for formatting, so I need to somehow escape it.

For example:

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

回答1:


As a workaround:

>>> d = {'hello': 'world', 'with:colon': 'moo'}
>>> '{hello} {}'.format(d['with:colon'],**d)
'world moo'
>>> '{hello} {0}'.format(d['with:colon'],**d)
'world moo'



回答2:


According to the documentation, what you are asking is simply not possible. Specifically,

Because arg_name is not quote-delimited, it is not possible to specify arbitrary dictionary keys (e.g., the strings '10' or ':-]') within a format string.




回答3:


You can't - the keys must be syntactically equivalent to Python identifiers. See Format String Syntax in the documentation:

replacement_field ::=  "{" [field_name] ["!" conversion] [":" format_spec] "}"
field_name        ::=  arg_name ("." attribute_name | "[" element_index "]")*
arg_name          ::=  [identifier | integer]
attribute_name    ::=  identifier



回答4:


As of python 3.6 you can solve this with the new f-string formating:

>>> d = {'hello': 'world', 'with:colon': 'moo'}
>>> print(f"with:colon is equal to {d['with:colon']}")
with:colon is equal to moo



回答5:


As @murgatroid99 points out in his answer, this isn't possible.

A work-around would be to replace the keys with keys that are valid:

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

Naturally, you might want to be careful if there is the possibility of conflicts with other keys.

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

Obviously, this assumes you can modify your format strings to suit. Ideally, just modify both ends to avoid colons all together.




回答6:


It's a pity that the built-in formatter doesn't allow that. An obvious syntax extension would be to allow keys to be quoted, if necessary. Your format string would be then like this:

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

Fortunately, it appears to be easy to extend the Formatter to provide this syntax, here's a POC implementation:

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)

Usage:

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


来源:https://stackoverflow.com/questions/19913504/how-do-i-escape-a-colon-in-python-format-when-using-kwargs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!