How can I match a Markdown code block with RegEx?

蓝咒 提交于 2020-08-24 17:58:12

问题


I am trying to extract a code block from a Markdown document using PCRE RegEx. For the uninitiated, a code block in Markdown is defined thus:

To produce a code block in Markdown, simply indent every line of the block by at least 4 spaces or 1 tab. A code block continues until it reaches a line that is not indented (or the end of the article).

So, given this text:

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

So far I have this RegEx:

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

But it simply captures each line prefixed with at least four spaces or one tab. It doesn't capture the whole block.

What I need help with is how to set the condition to capture everything after 4 spaces or 1 tab until you either get to a line that is not indented or the end of the text.

Here's an online work in progress:

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


回答1:


You should use begin/end-of-string markers (^ and $ in combination with the m modifier). Also, your test text had only 3 leading spaces in the final block:

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

With \R and the repetition you match one whole block with each single match, instead of a line per match.

See demo on regex101

Disclaimer: The rules of markdown are more complicated than the presented example text shows. For instance, when (nested) lists have code blocks in them, these need to be prefixed with 8, 12 or more spaces. Regular expressions are not suitable to identify such code blocks, or other code blocks embedded in markdown notation that uses the wider range of format combinations.




回答2:


Try this?

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

It will extract from your example

This must have three backticks
flanking it



回答3:


There are 3 ways to highlight code: 1) using start-of-line indentation 2) using 3 or more backticks enclosing a multiline block of code or 3) inline code.
1 and 3 are part of John Gruber original Markdown specification.
Here is the way to achieve this. You need to perform 3 separate regexp tests:

  1. Using indentation

     (?:\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) Using code block with backticks (vanilla markdown)

    (?:\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) Using code block with backticks with some class specifier (extended markdown)

    (?:\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. Using 1 or more backticks for inline code

     (?:\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
     )
    


来源:https://stackoverflow.com/questions/41351903/how-can-i-match-a-markdown-code-block-with-regex

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!