31

首先,我知道,PHP 已经有一个 Markdown 解析器。我也看了这个问题,但它没有回答我的问题。

显然,即使标题提到了 PHP,如果它与语言无关,因为我想知道我必须经过哪些步骤才能做到这一点。

我读过PEG,但我不得不承认,我并没有真正理解 PHP 解析器提供的示例。

我也读过CFG

我发现Zend_Markup_Parser_Textile似乎构建了一个所谓的“令牌树”(它是怎么回事?)但它目前无法使用。(顺便说一句,Textile 不是 Markdown)

所以,具体来说,你会怎么做呢?

显然,我虽然想使用正则表达式,但我很害怕。

因为 Markdown 支持同一元素的多种语法(Setext 和 atx)。

你能给出一些起点吗?

4

5 回答 5

38

你应该看看Parsedown

它以人们的方式解析 Markdown 文本。首先,它将文本分成几行。然后看看这些线是如何开始和相互关联的。最后,它会寻找特殊字符来识别内联元素。

于 2013-07-23T22:15:09.977 回答
11

PHP Markdown Extra似乎很流行,您可以从查看它的源代码开始。

于 2011-02-25T11:30:05.190 回答
5

此外,还有一个更快的 Markdown 面向对象实现:markdown-oo-php

于 2012-10-20T13:31:05.617 回答
2

使用正则表达式。

<?php

/**
 * Slimdown - A very basic regex-based Markdown parser. Supports the
 * following elements (and can be extended via Slimdown::add_rule()):
 *
 * - Headers
 * - Links
 * - Bold
 * - Emphasis
 * - Deletions
 * - Quotes
 * - Inline code
 * - Blockquotes
 * - Ordered/unordered lists
 * - Horizontal rules
 *
 * Author: Johnny Broadway <johnny@johnnybroadway.com>
 * Website: https://gist.github.com/jbroadway/2836900
 * License: MIT
 */
class Slimdown {
    public static $rules = array (
        '/(#+)(.*)/' => 'self::header',                           // headers
        '/\[([^\[]+)\]\(([^\)]+)\)/' => '<a href=\'\2\'>\1</a>',  // links
        '/(\*\*|__)(.*?)\1/' => '<strong>\2</strong>',            // bold
        '/(\*|_)(.*?)\1/' => '<em>\2</em>',                       // emphasis
        '/\~\~(.*?)\~\~/' => '<del>\1</del>',                     // del
        '/\:\"(.*?)\"\:/' => '<q>\1</q>',                         // quote
        '/`(.*?)`/' => '<code>\1</code>',                         // inline code
        '/\n\*(.*)/' => 'self::ul_list',                          // ul lists
        '/\n[0-9]+\.(.*)/' => 'self::ol_list',                    // ol lists
        '/\n(&gt;|\>)(.*)/' => 'self::blockquote ',               // blockquotes
        '/\n-{5,}/' => "\n<hr />",                                // horizontal rule
        '/\n([^\n]+)\n/' => 'self::para',                         // add paragraphs
        '/<\/ul>\s?<ul>/' => '',                                  // fix extra ul
        '/<\/ol>\s?<ol>/' => '',                                  // fix extra ol
        '/<\/blockquote><blockquote>/' => "\n"                    // fix extra blockquote
    );

    private static function para ($regs) {
        $line = $regs[1];
        $trimmed = trim ($line);
        if (preg_match ('/^<\/?(ul|ol|li|h|p|bl)/', $trimmed)) {
            return "\n" . $line . "\n";
        }
        return sprintf ("\n<p>%s</p>\n", $trimmed);
    }

    private static function ul_list ($regs) {
        $item = $regs[1];
        return sprintf ("\n<ul>\n\t<li>%s</li>\n</ul>", trim ($item));
    }

    private static function ol_list ($regs) {
        $item = $regs[1];
        return sprintf ("\n<ol>\n\t<li>%s</li>\n</ol>", trim ($item));
    }

    private static function blockquote ($regs) {
        $item = $regs[2];
        return sprintf ("\n<blockquote>%s</blockquote>", trim ($item));
    }

    private static function header ($regs) {
        list ($tmp, $chars, $header) = $regs;
        $level = strlen ($chars);
        return sprintf ('<h%d>%s</h%d>', $level, trim ($header), $level);
    }

    /**
     * Add a rule.
     */
    public static function add_rule ($regex, $replacement) {
        self::$rules[$regex] = $replacement;
    }

    /**
     * Render some Markdown into HTML.
     */
    public static function render ($text) {
        $text = "\n" . $text . "\n";
        foreach (self::$rules as $regex => $replacement) {
            if (is_callable ( $replacement)) {
                $text = preg_replace_callback ($regex, $replacement, $text);
            } else {
                $text = preg_replace ($regex, $replacement, $text);
            }
        }
        return trim ($text);
    }
}


echo Slimdown::render ("# Title

And *now* [a link](http://www.google.com) to **follow** and [another](http://yahoo.com/).

* One
* Two
* Three

## Subhead

One **two** three **four** five.

One __two__ three _four_ five __six__ seven _eight_.

1. One
2. Two
3. Three

More text with `inline($code)` sample.

> A block quote
> across two lines.

More text...");

来源https://gist.github.com/jbroadway/2836900

于 2020-06-07T22:55:16.050 回答
2

Ciconia - A New Markdown Parser for PHP 是我发现的一个很好的解析器。

你只需要做 3 件事:

1.根据文档安装Ciconia并解析文件。
2.添加相应的css主题,使其美观,如github markdown风格here
3. 添加语法高亮javascript,如google Javascript code prettifier

然后一切看起来都会很好。

如果你想要一个完整的例子,这里是我的 github 风格 Markdown 的工作演示:

<?php
header("Content-Type: text/html;charset=utf-8");
require 'vendor/autoload.php';
use Ciconia\Ciconia;
use Ciconia\Extension\Gfm;

$ciconia = new Ciconia();
$ciconia->addExtension(new Gfm\FencedCodeBlockExtension());
$ciconia->addExtension(new Gfm\TaskListExtension());
$ciconia->addExtension(new Gfm\InlineStyleExtension());
$ciconia->addExtension(new Gfm\WhiteSpaceExtension());
$ciconia->addExtension(new Gfm\TableExtension());
$ciconia->addExtension(new Gfm\UrlAutoLinkExtension());
$contents = file_get_contents('Readme.md');
$html = $ciconia->render($contents);
?>
<!DOCTYPE html>
<html>
    <head>
        <title>Excel to Lua table - Readme</title>
        <script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>
        <link rel="stylesheet" href="./github-markdown.css">
        <style>
            .markdown-body {
                box-sizing: border-box;
                min-width: 200px;
                max-width: 980px;
                margin: 0 auto;
                padding: 45px;
            }
        </style>
    </head>
    <body>
        <article class="markdown-body">
        <?php
            # Put HTML content in the document
            echo $html;
        ?>
        </article>
    </body>
</html>
于 2016-06-20T09:56:36.223 回答