The nl2br
过滤器无法正确处理标记对象。如果value
是Markup,那么插入的<br>
标签将被转义。为了解决这个问题,<br>
标签也必须是标记:
@app.template_filter()
@evalcontextfilter
def nl2br(eval_ctx, value):
_paragraph_re = re.compile(r'(?:\r\n|\r(?!\n)|\n){2,}')
result = u'\n\n'.join(u'<p>%s</p>' % p.replace(u'\n', Markup('<br>\n'))
for p in _paragraph_re.split(value))
if eval_ctx.autoescape:
result = Markup(result)
return result
注意:我将行结尾标准化为\n
.
这是对正在发生的事情的更详细的解释:
分裂Markup
对象,产生许多Markup
对象:
>>> Markup("hello there").split()
[Markup(u'hello'), Markup(u'there')]
根据Jinja 的标记文档 http://jinja.pocoo.org/docs/api/#jinja2.Markup:
对标记字符串的操作是标记感知的,这意味着所有参数都通过 escape() 函数传递。
回顾主要转变nl2br
,我们可以看到发生了什么以及为什么它不起作用:
result = u'\n\n'.join(u'<p>%s</p>' % p.replace(u'\n', u'<br>\n')
for p in _paragraph_re.split(value))
u'\n\n'
and u'<br>\n'
是 unicode 字符串,但是p
is Markup
已被分割value
,这是一个标记对象。p.replace
尝试将 unicode 字符串添加到 Markup 对象p
,但是标记对象首先正确地拦截并转义字符串。
The <p>
由于 Python 组装最终字符串的方式,标签不会被转义,因为%
在 unicode 字符串上调用格式化方法,它使用传递给它的元素的 unicode 表示形式。标记元素已被声明为安全的,因此它们不会进一步转义。result
最终作为 unicode 字符串。