从php中的Markdown生成目录

时间:2015-08-18 09:27:30

标签: php parsing markdown

我想从Markdown创建一个目录 例如,在stackedit.io https://stackedit.io/editor#table-of-contents插入时:

[TOC]

有没有办法从降价中产生这个?

E.g。如果你有:

## header 1
## header 2

ToC应该是:

<ol>
   <li><a href="#header1">Header 1</a></li>
   <li><a href="#header2">Header 2</a></li>
</ol>

我应该创建自己的降价解析器才能获得ToC吗?

2 个答案:

答案 0 :(得分:6)

以下是执行基本工作的函数:它返回已找到标题的JSON列表,每个标题都有其级别和文本。
此JSON元素可以进一步用于生成所需的HTML结构或其他任何内容。

原理图如下:

  1. 将markdown文件作为字符串获取,并将换行符标准化为\n(这对于下面的步骤3非常重要)
  2. 使用/^(?:=|-|#).*$/m应用一个简单的正则表达式PREG_OFFSET_CAPTURE:所以匹配以下所有行:
    • <h1>(当“=”)或<h2>(当“ - ”)标题
    • 时的“下划线”
    • 是标题(以“#”开头)
  3. 迭代匹配的行:
    • for“underliners”,查看上一行的源文件,该文件位于当前行偏移量与前一行换行符之间的字符串中;然后从下划线类型和上一行的文本中获取级别
    • 否则只需从当前行本身获取级别和文本
  4. 这是功能:

    function markdown_toc($file_path) {
      $file = file_get_contents($file_path);
    
      // ensure using only "\n" as line-break
      $source = str_replace(["\r\n", "\r"], "\n", $file);
    
      // look for markdown TOC items
      preg_match_all(
        '/^(?:=|-|#).*$/m',
        $source,
        $matches,
        PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE
      );
    
      // preprocess: iterate matched lines to create an array of items
      // where each item is an array(level, text)
      $file_size = strlen($source);
      foreach ($matches[0] as $item) {
        $found_mark = substr($item[0], 0, 1);
        if ($found_mark == '#') {
          // text is the found item
          $item_text = $item[0];
          $item_level = strrpos($item_text, '#') + 1;
          $item_text = substr($item_text, $item_level);
        } else {
          // text is the previous line (empty if <hr>)
          $item_offset = $item[1];
          $prev_line_offset = strrpos($source, "\n", -($file_size - $item_offset + 2));
          $item_text =
            substr($source, $prev_line_offset, $item_offset - $prev_line_offset - 1);
          $item_text = trim($item_text);
          $item_level = $found_mark == '=' ? 1 : 2;
        }
        if (!trim($item_text) OR strpos($item_text, '|') !== FALSE) {
          // item is an horizontal separator or a table header, don't mind
          continue;
        }
        $raw_toc[] = ['level' => $item_level, 'text' => trim($item_text)];
      }
    
      // create a JSON list (the easiest way to generate HTML structure is using JS)
      return json_encode($raw_toc);
    }
    

    以下是从home page of the link you provided返回的结果:

    [
      {"level":1,"text":"Welcome to StackEdit!"},
      {"level":2,"text":"Documents"},
      {"level":4,"text":"<\/i> Create a document"},
      {"level":4,"text":"<\/i> Switch to another document"},
      {"level":4,"text":"<\/i> Rename a document"},
      {"level":4,"text":"<\/i> Delete a document"},
      {"level":4,"text":"<\/i> Export a document"},
      {"level":2,"text":"Synchronization"},
      {"level":4,"text":"<\/i> Open a document"},
      {"level":4,"text":"<\/i> Save a document"},
      {"level":4,"text":"<\/i> Synchronize a document"},
      {"level":4,"text":"<\/i> Manage document synchronization"},
      {"level":2,"text":"Publication"},
      {"level":4,"text":"<\/i> Publish a document"},
      {"level":2,"text":"- Markdown, to publish the Markdown text on a website that can interpret it (**GitHub** for instance),"},
      {"level":2,"text":"- HTML, to publish the document converted into HTML (on a blog for example),"},
      {"level":4,"text":"<\/i> Update a publication"},
      {"level":4,"text":"<\/i> Manage document publication"},
      {"level":2,"text":"Markdown Extra"},
      {"level":3,"text":"Tables"},
      {"level":3,"text":"Definition Lists"},
      {"level":3,"text":"Fenced code blocks"},
      {"level":3,"text":"Footnotes"},
      {"level":3,"text":"SmartyPants"},
      {"level":3,"text":"Table of contents"},
      {"level":3,"text":"MathJax"},
      {"level":3,"text":"UML diagrams"},
      {"level":3,"text":"Support StackEdit"}
    ]
    

答案 1 :(得分:0)

添加目录不是正常markdown语法的一部分,或者在许多较大的markdown解析器中可用(

)。

然而,我在markdown解析器中添加了自动创建目录: https://github.com/PeterWaher/IoTGateway/tree/master/Content/Waher.Content.Markdown

它通过可插入的界面工作,使用与插入图像时相同的语法来包含多媒体。基于根据提供的URL计算的分级来选择多媒体模块。这允许您包含视频,音频,YouTube剪辑等。它还允许您插入目录。你只需写![Table of Contents](ToC)