我正在尝试实现 this Jinja nl2br 过滤器。除了它添加的 <br> 被转义外,它工作正常。这对我来说很奇怪,因为 <p> 没有被转义,而且它们都在同一个字符串中。

我正在使用 flask ,因此启用了 Jinja autoescape。当我发现 this guyautoescapeescape(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&lt;br&gt;
2</p>

<p>3&lt;br&gt;
4</p>

<p>5&lt;br&gt;
6&lt;br&gt;
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 字符串,但 pMarkupvalue 中分离出来的,它是一个标记对象。 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/

10-16 11:58