部分string格式

是否有可能使用高级string格式化方法进行部分string格式化,类似于string模板safe_substitute()函数?

例如:

 s = '{foo} {bar}' s.format(foo='FOO') #Problem: raises KeyError 'bar' 

您可以通过覆盖映射来欺骗它进行部分格式化:

 import string class FormatDict(dict): def __missing__(self, key): return "{" + key + "}" s = '{foo} {bar}' formatter = string.Formatter() mapping = FormatDict(foo='FOO') print(formatter.vformat(s, (), mapping)) 

印花

 FOO {bar} 

当然,这个基本的实现只适用于基本的情况。

如果你知道你以什么顺序格式化的东西:

 s = '{foo} {{bar}}' 

像这样使用它:

 ss = s.format(foo='FOO') print ss >>> 'FOO {bar}' print ss.format(bar='BAR') >>> 'FOO BAR' 

您不能同时指定foobar – 您必须按顺序执行。

.format()局限性 – 无法进行部分replace – 一直困扰着我。

在评估写了一个自定义的Formatter类之后 ,我们发现了一个更为简单的内置解决scheme: 模板string

它提供了类似的function,但也通过safe_substitute()方法提供了部分replace。 模板string需要$前缀(这感觉有点奇怪 – 但我认为整体解决scheme更好)。

 import string template = string.Template('${x} ${y}') try: template.substitute({'x':1}) # raises KeyError except KeyError: pass # but the following raises no error partial_str = template.safe_substitute({'x':1}) # no error # partial_str now contains a string with partial substitution partial_template = string.Template(partial_str) substituted_str = partial_template.safe_substitute({'y':2}) # no error print substituted_str # prints '12' 

在此基础上形成一个便捷包装:

 class StringTemplate(object): def __init__(self, template): self.template = string.Template(template) self.partial_substituted_str = None def __repr__(self): return self.template.safe_substitute() def format(self, *args, **kws): self.partial_substituted_str = self.template.safe_substitute(*args, **kws) self.template = string.Template(self.partial_substituted_str) return self.__repr__() >>> s = StringTemplate('${x}${y}') >>> s '${x}${y}' >>> s.format(x=1) '1${y}' >>> s.format({'y':2}) '12' >>> print s 12 

同样,基于Sven的答案,使用默认的string格式的包装:

 class StringTemplate(object): class FormatDict(dict): def __missing__(self, key): return "{" + key + "}" def __init__(self, template): self.substituted_str = template self.formatter = string.Formatter() def __repr__(self): return self.substituted_str def format(self, *args, **kwargs): mapping = StringTemplate.FormatDict(*args, **kwargs) self.substituted_str = self.formatter.vformat(self.substituted_str, (), mapping) 

不知道这是否可以作为一个快速的解决方法,但如何

 s = '{foo} {bar}' s.format(foo='FOO', bar='{bar}') 

? 🙂

如果你定义了自己的Formatter来覆盖get_value方法,你可以使用它来映射未定义的字段名称到任何你想要的:

http://docs.python.org/library/string.html#string.Formatter.get_value

例如,如果bar不在kwargs中,可以将bar映射到"{bar}"

但是,这需要使用Formatter对象的format()方法,而不是string的format()方法。

感谢琥珀的评论,我想出了这个:

 import string try: # Python 3 from _string import formatter_field_name_split except ImportError: formatter_field_name_split = str._formatter_field_name_split class PartialFormatter(string.Formatter): def get_field(self, field_name, args, kwargs): try: val = super(PartialFormatter, self).get_field(field_name, args, kwargs) except (IndexError, KeyError, AttributeError): first, _ = formatter_field_name_split(field_name) val = '{' + field_name + '}', first return val 
 >>> 'fd:{uid}:{{topic_id}}'.format(uid=123) 'fd:123:{topic_id}' 

试试这个。

对我来说这已经足够了:

 >>> ss = 'dfassf {} dfasfae efaef {} fds' >>> nn = ss.format('f1', '{}') >>> nn 'dfassf f1 dfasfae efaef {} fds' >>> n2 = nn.format('whoa') >>> n2 'dfassf f1 dfasfae efaef whoa fds' 

你可以使用functools的partialfunction

 import functools s = functools.partial("{foo} {bar}".format, foo="FOO") print s(bar="BAR") # FOO BAR 

还有一种方法可以实现这一点,即通过使用format%来replacevariables。 例如:

 >>> s = '{foo} %(bar)s' >>> s = s.format(foo='my_foo') >>> s 'my_foo %(bar)s' >>> s % {'bar': 'my_bar'} 'my_foo my_bar' 

假设你不会使用string,直到它被完全填满,你可以做这样的事情:

 class IncrementalFormatting: def __init__(self, string): self._args = [] self._kwargs = {} self._string = string def add(self, *args, **kwargs): self._args.extend(args) self._kwargs.update(kwargs) def get(self): return self._string.format(*self._args, **self._kwargs) 

例:

 template = '#{a}:{}/{}?{c}' message = IncrementalFormatting(template) message.add('abc') message.add('xyz', a=24) message.add(c='lmno') assert message.get() == '#24:abc/xyz?lmno' 

你可以把它包装在一个带有默认参数的函数中:

 def print_foo_bar(foo='', bar=''): s = '{foo} {bar}' return s.format(foo=foo, bar=bar) print_foo_bar(bar='BAR') # ' BAR'