2015-08-18 4 views
11

Я хотел бы создать оглавление из Markdown.
Например, в stackedit.iohttps://stackedit.io/editor#table-of-contents при вставке:Создать оглавление от Markdown в php

[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> 

Должен ли я создать свой собственный уценки анализатор просто получить ТОС?

+2

Зачем изобретать колесо? http://parsedown.org/ – BenM

+1

Я использую parsedown, но он автоматически не создает оглавление –

+0

'[TOC]' не является уценкой акций. – BenM

ответ

6

Ниже приведена функция, которая выполняет важную работу: она возвращает список найденных заголовков JSON, каждый со своим уровнем и текстом.
Этот элемент JSON может также использоваться для создания необходимой структуры HTML или чего-либо еще.

Схематично это работает так:

  1. Получить файл уценки в виде строки, и нормализовать разрывы строк только \n (это важно для шага # 3 ниже)
  2. Применить простой регулярному_выражению /^(?:=|-|#).*$/m с PREG_OFFSET_CAPTURE: так соответствует всем строкам, которые либо:
    • являются "underliners" из <h1> (когда "=") или <h2> (когда "-") названий
    • являются названия сами по себе (начиная с «#»)
  3. Iterate совпавшие строки:
    • для «underliners», посмотреть на исходный файл для предыдущей строки, расположенной в строке между текущее смещение линии и предыдущий разрыв строки; затем получить уровень от типа underliner и текста из предыдущей строки
    • иначе просто получить уровень и текст от текущей строки самого

Вот функция:

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"} 
] 
0

Добавление оглавления не является частью стандартного синтаксиса разметки или доступно (пока) во многих более сильных анализаторах разметки.

Я однако добавил автоматическое создание оглавления в моей уценке парсере: https://github.com/PeterWaher/IoTGateway/tree/master/Content/Waher.Content.Markdown

Он работает через вставной интерфейс для включения мультимедиа, используя тот же синтаксис, что и при вставке изображений. Мультимедийный модуль выбирается на основе оценки, рассчитанной по предоставленному URL. Это позволяет включать видео, аудио, клипы YouTube и т. Д.Он также позволяет вставлять оглавление. Вы просто пишете ![Table of Contents](ToC).

Смежные вопросы