我正在尝试实现 this Jinja nl2br
过滤器。除了它添加的 <br>
被转义外,它工作正常。这对我来说很奇怪,因为 <p>
没有被转义,而且它们都在同一个字符串中。
我正在使用 flask ,因此启用了 Jinja autoescape
。当我发现 this guy 说 autoescape
和 escape(value)
可能导致双重转义时,我真的很有希望,但删除 escape()
并没有帮助。
这是我修改后的代码及其输出:
@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>' % escape(p.replace(u'\r\n', u'<br>\n')) for p in _paragraph_re.split(value))
if eval_ctx.autoescape:
result = Markup(result)
return result
输入:
u'1\r\n2\r\n\r\n3\r\n4\r\n\r\n5\r\n6\r\n7'
输出:
<p>1<br>
2</p>
<p>3<br>
4</p>
<p>5<br>
6<br>
7</p>
所需的输出:
<p>1<br>2</p>
<p>3<br>4</p>
<p>5<br>6<br>7</p>
什么可能导致
<br>
被转义但允许 <p>
? 最佳答案
nl2br
过滤器不能正确处理标记对象。如果 value
是 Markup,那么插入的 <br>
标签将被转义。要修复它,<br>
标签也必须是 Markup:
@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's documentation for Markup :
回顾
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'
和 u'<br>\n'
是 unicode 字符串,但 p
是 Markup
从 value
中分离出来的,它是一个标记对象。 p.replace
尝试将 unicode 字符串添加到 Markup 对象 p
,但 Markup 对象首先正确拦截并转义字符串。<p>
标签不会因为 Python 组装最终字符串的方式而被转义,因为 %
格式化方法是在 unicode 字符串上调用的,它使用传递给它的元素的 unicode 表示。 Markup 元素已经被声明为安全的,所以它们不会再被转义。 result
最终是一个 unicode 字符串。关于python - 为什么这个 Jinja nl2br 过滤器会转义 <br >'s but not <p>' s?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12523725/