【问题标题】:How can I match a Markdown code block with RegEx?如何将 Markdown 代码块与 RegEx 匹配?
【发布时间】:2017-05-12 03:18:33
【问题描述】:

我正在尝试使用 PCRE RegEx 从 Markdown 文档中提取 code block。对于初学者,Markdown 中的代码块是这样定义的:

要在 Markdown 中生成代码块,只需缩进每一行 至少用 4 个空格或 1 个制表符隔开。 代码块一直持续到没有缩进的行(或文章末尾)。

因此,鉴于此文本:

This is a code block:

    I need capturing along with
    this line

This is a code fence below (to be ignored):

``` json
This must have three backticks
flanking it
```

I love `inline code` too but don't capture

and one more short code block:

    Capture me

到目前为止,我有这个正则表达式:

(?:[ ]{4,}|\t{1,})(.+)

但它只是捕获以至少四个空格或一个制表符为前缀的每一行。它不会捕获整个块。

我需要帮助的是如何将条件设置为在 4 个空格或 1 个制表符之后捕获所有内容,直到到达未缩进的行或文本的结尾。 p>

这是一个正在进行的在线工作:

https://www.regex101.com/r/yMQCIG/5

【问题讨论】:

  • 您在正则表达式上设置了哪些选项?如果您想将文本作为一个块而不是逐行分析,请尝试/regex/m,其中m 表示打开“多行”选项。
  • 我尝试在 regex101.com 上切换 m 开关,但它对我目前拥有的 RegEx 没有帮助。更新了问题以包含指向我拥有的在线 RegEx 的链接。
  • 在 regex101.com 上启用多行开关 ('s') 实际上会导致我的问题中的 RegEx 匹配所有不正确的示例文本...
  • Capture me 缩进了 3 个空格,见 regex101.com/r/yMQCIG/3 有 4 个空格。
  • 一个关于 Stack Overflow 的正则表达式问题与先前的尝试是世界第八大奇迹!干得好。

标签: regex markdown


【解决方案1】:

您应该使用字符串开始/结束标记(^$m 修饰符结合使用)。此外,您的测试文本在最后一个块中只有 3 个前导空格:

^((?:(?:[ ]{4}|\t).*(\R|$))+)

使用\R 和重复,您可以将一个完整的块与每个匹配项匹配,而不是每个匹配项匹配一行。

regex101上查看演示

免责声明: Markdown 的规则比示例文本显示的要复杂。例如,当(嵌套)列表中有代码块时,这些代码块需要以 8、12 或更多空格作为前缀。正则表达式不适合识别此类代码块,或嵌入在使用更广泛格式组合的降价符号中的其他代码块。

【讨论】:

  • 如果缩进文本是嵌套在列表项中的段落怎么办?这没有考虑到这一点。
  • @Waylan,确实,它并不是为了解释这一点。处理与缩进块结合的列表的规则更复杂,因为前缀空格的数量需要为 8、12 或与列表缩进级别相对应的任何内容。我怀疑正则表达式是否适合这种解析。
  • @trincot,我同意,这是我的观点。虽然您的解决方案适用于简单的情况,但它并不是一个完整的解决方案。如果 OP 想要一个完整的解决方案,那么 REGEX 不是答案。
  • 我们同意这一点。我在答案中添加了免责声明。
【解决方案2】:

试试这个?

[a-z]*\n[\s\S]*?\n

它将从您的示例中提取

This must have three backticks
flanking it

【讨论】:

    【解决方案3】:

    有 3 种方法突出显示代码:1) 使用行首缩进 2) 使用 3 个或更多反引号包围多行代码块或 3) 内联代码。
    1 和 3 是 John Gruber original Markdown specification 的一部分。
    这是实现这一目标的方法。您需要执行 3 个单独的正则表达式测试:

    1. 使用缩进

       (?:\n{2,}|\A)                   # Starting at beginning of string or with 2 new lines
       (?<code_all>
           (?:
               (?<code_prefix>         # Lines must start with a tab or a tab-width of spaces
                   [ ]{4}
                   |
                   \t
               )
               (?<code_content>.*\n+)  # with some content, possibly nothing followed by a new line
           )+
       )
       (?<code_after>
           (?=^[ ]{0,4}\S)             # Lookahead for non-space at line-start
           |
           \Z                          # or end of doc
       )
      

    2a) 使用带反引号的代码块(原版降价)

        (?:\n+|\A)?                         # Necessarily at the begining of a new line or start of string
        (?<code_all>
            (?<code_start>
                [ ]{0,3}                    # Possibly up to 3 leading spaces
                \`{3,}                      # 3 code marks (backticks) or more
            )
            \n+
            (?<code_content>.*?)            # enclosed content
            \n+
            (?<!`)
            \g{code_start}                  # balanced closing block marks
            (?!`)
            [ \t]*                          # possibly followed by some space
            \n
        )
        (?<code_trailing_new_line>\n|\Z)    # and a new line or end of string
    

    2b) 使用带有类说明符的反引号的代码块(扩展降价)

        (?:\n+|\A)?                 # Necessarily at the beginning of a new line
        (?<code_all>
            (?<code_start>
                [ ]{0,3}            # Possibly up to 3 leading spaces
                \`{3,}              # 3 code marks (backticks) or more
            )
            [ \t]*                  # Possibly some spaces or tab
            (?:
                (?:
                    (?<code_class>[\w\-\.]+)    # or a code class like html, ruby, perl
                    (?:
                        [ \t]*
                        \{(?<code_def>[^\}]+)\} # a definition block like {.class#id}
                    )?                          # Possibly followed by class and id definition in curly braces
                )
                |
                (?:
                    [ \t]*
                    \{(?<code_def>[^\}]+)\} # a definition block like {.class#id}
                )                           # Followed by class and id definition in curly braces
            )
            \n+
            (?<code_content>.*?)    # enclosed content
            \n+
            (?<!`)
            \g{code_start}          # balanced closing block marks
            (?!`)
        )
        (?:\n|\Z)                # and a new line or end of string
    
    1. 对内联代码使用 1 个或多个反引号

       (?<!\\)                     # Ensuring this is not escaped
       (?<code_all>
           (?<code_start>\`{1,})   # One or more backtick(s)
           (?<code_content>.+?)    # Code content inbetween back sticks
           (?<!`)                  # Not preceded by a backtick
           \g{code_start}          # Balanced closing backtick(s)
           (?!`)                   # And not followed by a backtick
       )
      

    【讨论】:

    • 示例 3 的模式错误 - 与模式 1 相同。复制粘贴错误?
    • 是的,复制/粘贴错误。它应该是: (? (?`{1,}) # 一个或多个反引号 (?.+?) # 反引号之间的代码内容 (?) # Not preceded by a backtick \g{code_start} # Balanced closing backtick(s) (?!) # 后面没有反引号 ) 见这里 regex101.com/r/C2Vl9M/1>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-01
    • 2019-04-13
    • 2012-05-21
    • 1970-01-01
    相关资源
    最近更新 更多