Как бы вы пошли о разборе Markdown?
Редактировать: я недавно узнал о проекте CommonMark, который правильно идентифицирует и устраняет неоднозначности в исходной спецификации Markdown. http://commonmark.org/ Имеет отличную поддержку библиотеки C#.
Вы можете найти синтаксис здесь.
Источник, который следует за загрузкой, написан на Perl, который я не собираюсь чтить. Он пронизан регулярными выражениями и использует хеши MD5 для экранирования определенных символов. Что-то не так в этом!
Я собираюсь жестко написать парсер для Markdown. Каков опыт с этим?
Если у вас нет ничего значащего, чтобы сказать о фактическом разборе Markdown, сэкономьте мне время. (Это может показаться грубым, но да, я ищу понимание, а не решение, то есть стороннюю библиотеку).
Чтобы помочь с ответами, регулярные выражения предназначены для определения шаблонов! НЕ анализировать всю грамматику. То, что люди думают сделать это - это foobar.
- Если вы думаете об уценке, она основывается на концепции абзацев.
- Таким образом, разумным подходом может быть разделение ввода на параграфы.
- Есть много видов абзацев, например, заголовок, текст, список, цитата и код.
- Таким образом, задача состоит в том, чтобы определить эти пункты и в каком контексте они встречаются.
Я вернусь с решением, как только я найду, что стоит поделиться.
10 ответов
Единственная известная мне реализация уценки, в которой используется настоящий парсер, - это разметка Jon MacFarleane's peg-markdown. Его синтаксический анализатор основан на генераторе синтаксического анализатора выражения синтаксического анализа, называемом peg.
РЕДАКТИРОВАТЬ: Маурисио Фернандес недавно выпустил парсер Simple Markup Markdown, который он написал как часть своего движка OcsiBlog. Поскольку синтаксический анализатор написан на OCaml, он чрезвычайно прост и короток (268 SLOC для синтаксического анализатора, 43 SLOC для эмиттера HTML), но при этом невероятно быстрый (на 20% быстрее, чем дисконтный (написан на оптимизированном вручную C) и в шестьсот раз быстрее чем BlueCloth ( Ruby)), несмотря на то, что он еще даже не оптимизирован для производительности. Поскольку он предназначен только для внутреннего использования самим Маурисио для своего блога, существует несколько отклонений от официальной спецификации Markdown, но Маурисио создал ветку, которая отменяет большинство этих изменений.
На прошлой неделе я выпустил новую реализацию Markdown Java на основе парсера, которая называется pegdown. pegdown использует синтаксический анализатор PEG для создания абстрактного синтаксического дерева, которое впоследствии записывается в HTML. Как таковой, он довольно чистый и намного легче читать, поддерживать и расширять, чем подход, основанный на регулярных выражениях. Грамматика PEG основана на реализации Джона Макфарлейнса C "peg-markdown".
Может быть, что-то интересное для вас...
Если бы я попытался проанализировать уценку (и ее расширение Markdown extra), я думаю, что я бы попытался использовать конечный автомат и анализировать его по одному символу за раз, связывая вместе некоторые внутренние структуры, представляющие фрагменты текста, по мере продвижения, один раз все анализируется, генерируя выходные данные всех объектов, соединенных вместе.
По сути, я строил бы дерево, похожее на мини-DOM, когда читал входной файл.
Чтобы сгенерировать вывод, я бы просто прошел через дерево и вывел HTML или что-нибудь еще (PS, LaTex, RTF,...)
Вещи, которые могут увеличить сложность:
Тот факт, что вы можете смешивать HTML и уценку, хотя правило может быть легко реализовано: просто игнорируйте все, что находится между двумя сбалансированными тегами, и выводите его дословно.
URL-адреса и заметки могут иметь свою ссылку внизу текста. Использование структур данных для гиперссылок может просто записать что-то вроде:
[my text to a link][linkkey] results in a structure like: URLStructure: | InnerText : "my text to a link" | Key : "linkkey" | URL : <null>
Заголовки могут быть определены с подчеркиванием, что может заставить нас использовать простую структуру данных для общего абзаца и изменять его свойства при чтении файла:
ParagraphStructure: | InnerText : the current paragraph text | (beginning of line until end of line). | HeadingLevel : <null> or 1-4 when we can assess | that paragraph heading level, if any.
Во всяком случае, только некоторые мысли.
Я уверен, что есть много мелких деталей, о которых нужно позаботиться, и я почти уверен, что регулярные выражения могут пригодиться во время процесса.
В конце концов, они должны были обрабатывать текст.
Я, вероятно, прочитал бы спецификацию синтаксиса достаточно раз, чтобы узнать ее и почувствовать, как ее анализировать.
Чтение существующего кода синтаксического анализатора, конечно, прекрасно, как для того, чтобы увидеть, что кажется основным источником сложности, так и для использования каких-либо специальных хитрых приемов. Использование контрольной суммы MD5 кажется немного странным, но я недостаточно изучил код, чтобы понять, почему он выполняется. Комментарий в рутине называется _EscapeSpecialChars()
состояния:
Мы заменяем каждый такой символ соответствующим значением контрольной суммы MD5; это, вероятно, излишне, но оно должно предотвратить случайное столкновение с escape-значениями.
Замена одного символа на полный MD5 кажется экстравагантной, но, возможно, это действительно имеет смысл.
Конечно, было бы разумно подумать о создании "истинного" синтаксиса для такого инструмента, как Flex, чтобы выйти из трюка с регулярными выражениями.
Если Perl не ваша вещь, есть реализации Markdown по крайней мере на 10 других языках. Они, вероятно, не все имеют 100% совместимость, но, как правило, довольно близки.
MarkdownPapers - это другая реализация Java, синтаксический анализатор которой определен в грамматике JavaCC.
Если вы используете язык программирования, который имеет более трех других пользователей, вы сможете найти библиотеку, чтобы проанализировать его для вас. Быстрый поиск в Google показывает библиотеки для CL, Haskell, Python, JavaScript, Ruby и так далее. Маловероятно, что вам придется изобретать это колесо.
Если вам действительно нужно написать это с нуля, я рекомендую написать правильный парсер. С этой техникой вам не придется избегать вещей с хэшами MD5. (Я согласен, что если вам нужно сделать что-то подобное, пришло время пересмотреть ваш дизайн.)
Здесь вы можете найти JavaScript-реализацию Markdown. Он также сильно зависит от регулярных выражений, так как это самый быстрый и простой способ разбора текста.
Но это экономит часть MD5.
Я не могу помочь напрямую с кодировкой синтаксического анализа, но, возможно, эта ссылка может помочь вам так или иначе.
Существуют библиотеки, доступные на нескольких языках, включая php, ruby, java, C#, javascript. Я бы посоветовал взглянуть на некоторые из них для идей.
Это зависит от того, какой язык вы хотите использовать, для наилучшего способа его реализации, будут идиоматические и не идиоматические способы сделать это.
Регулярные выражения работают в Perl, потому что Perl и регулярные выражения являются лучшими друзьями.
Markdown - это JAWL (просто еще один вики-язык)
Существует множество вики с открытым исходным кодом, с которыми вы можете ознакомиться с кодом парсера. Большинство используют REGEX
Посмотрите викитюру на вики, в ней есть интересный многопроходный конвейер форматирования, очень хорошая техника - смотрите /core/Formatter.cs и /core/FormatterPipeline.cs
Лучше всего использовать / присоединиться к существующему проекту, такие вещи всегда намного сложнее, чем кажутся