0

我想为 Python-Markdown 添加一个额外的语法:如果n是一个正整数,>>n应该扩展为<a href="#post-n">n</a>. (双尖括号 ( ) 是在图像板论坛>>中创建链接的常规语法。)

默认情况下,Python-Markdown 扩展>>n为嵌套块引用:<blockquote><blockquote>n</blockquote></blockquote>. 有没有办法从 中创建链接>>n,同时保留 blockquote 的默认行为的其余部分?换句话说,如果x是正整数,>>x应该展开成链接,但如果x不是正整数,>>x仍然应该展开成嵌套的块引用。

我已经阅读了相关的 wiki 文章:Tutorial 1 Writing Extensions for Python Markdown。根据我在 wiki 中学到的知识,我编写了一个自定义扩展:

import markdown
import xml.etree.ElementTree as ET
from markdown.extensions import Extension
from markdown.inlinepatterns import Pattern


class ImageboardLinkPattern(Pattern):
    def handleMatch(self, match):
        number = match.group('number')
        # Create link.
        element = ET.Element('a', attrib={'href': f'#post-{number}'})
        element.text = f'>>{number}'
        return element


class ImageboardLinkExtension(Extension):
    def extendMarkdown(self, md):
        IMAGEBOARD_LINK_RE = '>>(?P<number>[1-9][0-9]*)'
        imageboard_link = ImageboardLinkPattern(IMAGEBOARD_LINK_RE)
        md.inlinePatterns['imageboard_link'] = imageboard_link


html = markdown.markdown('>>123',
                         extensions=[ImageboardLinkExtension()])
print(html)

但是,>>123仍然产生<blockquote><blockquote>123</blockquote></blockquote>. 上面的实现有什么问题?

4

1 回答 1

0

问题是您的新语法与先前存在的块引用语法冲突。如果曾经调用过您的扩展程序,它可能会起作用。然而,由于冲突,这从未发生过。请注意,它们是五种类型的处理器。据记载

  • 在将源传递给解析器之前,预处理器会更改源。
  • 块处理器处理由空行分隔的文本块。
  • 树处理器修改构造的 ElementTree
  • 内联处理器是用于内联元素的常见树处理器,例如*strong*.
  • 后处理器在解析器返回之前对其输出进行处理。

这里重要的是处理器按该顺序运行。换句话说,所有块处理器都在运行任何内联处理器之前运行。因此,blockquote 块处理器首先在您的输入上运行并删除双尖括号,将行的其余部分包装在双blockquote标签中。当您的内联处理器看到文档时,您的正则表达式将不再匹配,因此永远不会被调用。

话虽如此,内联处理器是实现链接语法的正确方法。但是,您需要做两件事之一才能使其工作。

  1. 更改语法,使其不会与任何先前存在的语法发生冲突;或者
  2. 更改块引用行为以避免冲突。

就个人而言,我会推荐选项 1,但我了解您正在尝试从另一个环境实现预先存在的语法。因此,如果您想探索选项 2,那么我建议您可能使 blockquote 语法更严格一些。例如,虽然不是必需的,但推荐的语法是始终在块引用中的尖括号后插入一个空格。将BlockquoteProcessor更改为需要空间应该相对简单,这将导致您的语法不再冲突。

这实际上很简单。正如您可能注意到的,整个语法是通过一个相当简单的正则表达式定义的:

RE = re.compile(r'(^|\n)[ ]{0,3}>[ ]?(.*)')

您只需要重写它,以便不再接受 0 空格(> 而不是>[ ]?)。首先导入现有处理器并将其子类化,然后覆盖正则表达式:

from markdown.blockprocessors import BlockquoteProcessor

class CustomBlockquoteProcessor(BlockquoteProcessor):
    RE = re.compile(r'(^|\n)[ ]{0,3}> (.*)')

最后,您只需要告诉 Markdown 使用您的自定义类而不是默认类。将以下内容添加到extendMarkdown您的类的方法中ImageboardLinkExtension

md.parser.blockprocessors.register(CustomBlockQuoteProcessor(md.parser), 'quote', 20)

现在,blockquote 语法将不再与您的链接语法发生冲突,您将有机会在文本上运行您的代码。请注意始终为任何实际的块引用包含现在所需的空间。

于 2021-09-28T13:21:54.090 回答