为字符串格式添加自定义转换类型
Posted
技术标签:
【中文标题】为字符串格式添加自定义转换类型【英文标题】:Add custom conversion types for string formatting 【发布时间】:2013-11-08 16:46:09 【问题描述】:python 中有没有为字符串格式添加额外的转换类型?
在基于%
的字符串格式中使用的标准转换类型是s
用于字符串,d
用于小数等。我想做的是添加一个我可以指定的新字符将返回要插入的字符串的自定义处理程序(例如 lambda 函数)。
例如,我想添加h
作为转换类型,以指定字符串应该转义以便在html 中使用。举个例子:
#!/usr/bin/python
print "<title>%(TITLE)h</title>" % "TITLE": "Proof that 12 < 6"
这将在"TITLE"
上使用cgi.escape
来产生以下输出:
<title>Proof that 12 < 6</title>
【问题讨论】:
您不能为字符串格式添加新的占位符类型,但您始终可以将输入数据放入一个函数中,该函数将以字符串形式返回您想要的输出。'%(TITLE)s' % 'TITLE': my_html_formatter( 'Proof that 12 < 6' )
谢谢,我知道了。我有一堆不同的字符串要传入,我希望能想出一个比单独将它们全部传递给函数更好的方法。我还希望能够以不同的格式多次使用相同的键(例如“TITLE”)。
【参考方案1】:
您可以为 html 模板创建自定义格式化程序:
import string, cgi
class Template(string.Formatter):
def format_field(self, value, spec):
if spec.endswith('h'):
value = cgi.escape(value)
spec = spec[:-1] + 's'
return super(Template, self).format_field(value, spec)
print Template().format('0:h 1:d', "<hello>", 123)
请注意,所有转换都发生在模板类内部,不需要更改输入数据。
【讨论】:
有趣。我喜欢不必使用自定义类型的想法。在选择答案之前,我将尝试两种方法,看看哪种效果更好。 我最终选择了这种方法,因为它不需要将所有内容包装在覆盖__format__
的自定义类型中。但是,您也可以将它与覆盖 __format__
的自定义类型结合使用,而不会出现任何问题。
为更准确的规格处理而编辑。
请注意,Formatter
类上还有一个更简单的 convert_field
方法,用于处理格式字段转换,例如内置的 !s
和 !r
。【参考方案2】:
不适用于%
格式,不,不可扩展。
您可以在使用为str.format()
和format()
定义的较新的format string syntax 时指定不同的格式选项。自定义类型可以实现__format__()
方法,并且将使用模板字符串中使用的格式规范调用该方法:
import cgi
class HTMLEscapedString(unicode):
def __format__(self, spec):
value = unicode(self)
if spec.endswith('h'):
value = cgi.escape(value)
spec = spec[:-1] + 's'
return format(value, spec)
这确实要求您为字符串使用自定义类型:
>>> title = HTMLEscapedString(u'Proof that 12 < 6')
>>> print "<title>:h</title>".format(title)
<title>Proof that 12 < 6</title>
在大多数情况下,在将字符串传递给模板之前对其进行格式化会更容易,或者使用专用的 HTML 模板库,例如 Chameleon、Mako 或 Jinja2;这些为您处理 HTML 转义。
【讨论】:
谢谢。我刚刚找到了相同的解决方案,但是您的示例确实很有用。 这个类对我来说没有多大意义,你可以简单地说":s".format(cgi.escape(title)...
——这正是 OP 试图避免的。
@thg435:这就是我最后所说的。它主要是一个示例,说明如何使用自定义格式规范挂钩字符串格式。
@thg435:这确实提供了更多的灵活性。例如,我可以使用不同的格式/转换类型多次使用相同的格式键。它还封装了 HTML 转义,因此如果我想做除cgi.escape
之外的其他事情,例如,我只需在一个地方更改它,而无需考虑其他任何地方。【参考方案3】:
我参加聚会有点晚了,但这是我所做的,基于https://mail.python.org/pipermail/python-ideas/2011-March/009426.html 中的一个想法
>>> import string, cgi
>>> from xml.sax.saxutils import quoteattr
>>> class MyFormatter(string.Formatter):
def convert_field(self, value, conversion, _entities='"': '"'):
if 'Q' == conversion:
return quoteattr(value, _entities)
else:
return super(MyFormatter, self).convert_field(value, conversion)
>>> fmt = MyFormatter().format
>>> fmt('0!Q', '<hello> "world"')
'"<hello> "world""'
【讨论】:
以上是关于为字符串格式添加自定义转换类型的主要内容,如果未能解决你的问题,请参考以下文章