2012-06-29 6 views
5

У меня есть конвертер bbcode -> html, который реагирует на событие изменения в текстовом поле. В настоящее время это делается с использованием ряда регулярных выражений, и существует ряд патологических случаев. Я всегда хотел заострить карандаш на этой грамматике, но не хотел вдаваться в бритье яков. Но ... недавно я узнал о pegjs, который кажется довольно полной реализацией генерации парсера PEG. У меня есть большая часть указанной грамматики, но теперь мне осталось интересно, подходит ли это полномасштабному парсеру.Использование PEG Parser для BBode Parsing: pegjs или ... что?

Мои конкретные вопросы:

  1. Поскольку мое приложение полагается на перевод, что я могу HTML и оставить остальное в качестве исходного текста, делает реализацию BBCode с использованием парсер, который может потерпеть неудачу на косметическим смысле ошибки синтаксиса ? Например: [url=/foo/bar]click me![/url], несомненно, будет успешным после ввода закрывающей скобки на теге закрытия. Но что бы тогда увидел пользователь? С регулярным выражением я могу просто игнорировать несоответствующие вещи и рассматривать его как обычный текст для целей предварительного просмотра. С формальной грамматикой я не знаю, возможно ли это, потому что я полагаюсь на создание HTML из дерева синтаксического анализа и что не удается разобрать ... что?

  2. Непонятно, где должны быть сделаны преобразования. В формальном анализаторе на основе lex/yacc я бы имел заголовочные файлы и символы, обозначающие тип узла. В pegjs я получаю вложенные массивы с текстом узла. Я могу испускать переведенный код как действие генерируемого парсером pegjs, но кажется, что запах кода сочетается с парсером и эмиттером. Однако, если я позвоню PEG.parse.parse(), я получаю ответ что-то вроде этого:

[ 
     [ 
      "[", 
      "img", 
      "", 
      [ 
      "/", 
      "f", 
      "o", 
      "o", 
      "/", 
      "b", 
      "a", 
      "r" 
      ], 
      "", 
      "]" 
     ], 
     [ 
      "[/", 
      "img", 
      "]" 
     ] 
    ]

дается грамматика как:

document 
    = (open_tag/close_tag/new_line/text)* 

open_tag 
    = ("[" tag_name "="? tag_data? tag_attributes? "]") 


close_tag 
    = ("[/" tag_name "]") 

text 
    = non_tag+ 

non_tag 
    = [\n\[\]] 

new_line 
    = ("\r\n"/"\n") 

Я сокращающий грамматику, конечно, но ты Получите эту идею. Итак, если вы заметили, в массиве массивов нет контекстуальной информации, которая говорит мне, какой у меня есть узел, и мне осталось сделать сравнения строк снова даже подумал, что парсер уже сделал это. Я ожидаю, что можно определить обратные вызовы и использовать действия для их запуска во время синтаксического разбора, но в Интернете есть небольшая информация о том, как это можно сделать.

Я лаю неправильное дерево? Должен ли я вернуться к просмотру регулярных выражений и забыть о разборе?

Благодаря

+0

Steve, ваш вопрос очень интересный (+1), я просто хочу сделать то же самое в расширении: разбор BBCode в текстовом поле (к сожалению, это формат, который по-прежнему используется форумом) и создать «живую» «Предварительный просмотр из введенного текста с использованием PEG.js или всего остального, кроме регулярных выражений. Вам удалось создать грамматику для парсера BBCode? Не могли бы вы поделиться своим решением через GitHub или что-нибудь еще? Это очень помогло бы мне. Большое спасибо заранее! – Sk8erPeter

+0

Я использовал парсер bbcode [patorjk] (https://github.com/patorjk/Extendible-BBCode-Parser). Отлично работает и может быть изменен в соответствии с вашими потребностями, если у вас есть специальные теги. –

+0

Спасибо, я уже видел эту библиотеку, но она использует регулярные выражения, которых я хотел избежать, потому что теоретически разбор BBCode с использованием регулярных выражений не может быть выполнен без ошибок ([»» link] (http: // kore- nordmann.de/blog/do_NOT_parse_using_regexp.html)) в некоторых случаях, например при их вложении друг в друга и т. д. Вот почему я хотел это сделать, используя синтаксический анализ выражения грамматического формализма. Так вы не пытались улучшить грамматику, которую вы начали? :) Разве вы не разделили его? :) – Sk8erPeter

ответ

2

Что касается вашего первого вопроса я имею tosay, что предварительный просмотр будет трудно. Проблемы, которые вы указали в отношении того, что синтаксический анализатор не поймет, что ввод «работа в процессе», верны. Peg.js сообщает вам, в какой момент ошибка, так что, возможно, вы могли бы взять эту информацию и вернуться на несколько слов и снова проанализировать или если отсутствующий тег конца попробует добавить его в конце.

Вторая часть вашего вопроса проще, но после этого ваша грамматика не будет выглядеть так красиво. В основном то, что вы сделать, это положить обратные вызовы на каждом правиле, так, например,

text 
    = text:non_tag+ { 
    // we captured the text in an array and can manipulate it now 
    return text.join(""); 
    } 

На данный момент вы должны написать эти обратные вызовы встроенными в вашей грамматике. Сейчас я делаю много всего этого на работе, поэтому я могу сделать pre.js pullrequest, чтобы исправить это. Но я не уверен, когда найду время для этого.

1

Попробуйте что-нибудь вроде этого правила замены. Вы на правильном пути; вы просто должны сказать ему, чтобы собрать результаты.

текст = результат: non_tag + {return result.join (''); }

3

Первый вопрос (грамматика для неполных текстов):

Вы можете добавить

incomplete_tag = ("[" tag_name "="? tag_data? tag_attributes?) 
//       the closing bracket is omitted ---^ 

послеopen_tag и изменить document включить неполную тег в конце. Хитрость заключается в том, что вы предоставляете парсеру все необходимые производные до всегда синтаксический анализ, но действительные первые. Затем вы можете игнорировать incomplete_tag во время предварительного просмотра.

Второй вопрос (как включить действия):

Вы пишете, так называемые действия после выражения. Действие - это код Javascript, заключенный в фигурные скобки и разрешенный после выражения pegjs, i. е. также в середине производства!

Практически такие действия, как { return result.join("") }, практически всегда необходимы, поскольку pegjs разбивается на отдельные символы. Также могут быть возвращены сложные вложенные массивы. Поэтому я обычно пишу вспомогательные функции в инициализаторе pegjs во главе грамматики, чтобы действия были небольшими. Если вы тщательно выберете имена функций, действие будет самодокументировано.

Для примера см. PEG for Python style indentation. Отказ от ответственности: это мой ответ.

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

  • Нет связанных вопросов^_^