Как пометить положение в потоке, чтобы вернуться к нему позже? - PullRequest
1 голос
/ 13 мая 2019

Справочная информация:

Я пытаюсь реализовать простой (?) Язык разметки, который будет использоваться для написания романов.

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

Базовая структура хорошо известна: @part{title}, @chapter{title} и @scene[{title}] имеют обычные значения, а двойные - \n указываютразрыв абзаца.

Особенности включают в себя:

  • @ speach [динамик] {высказывание, возможно, сложное}
  • @ стресс {что-то, что должно быть визуально улучшено}
  • @ standout {какая-то часть, которая должна иметь другое визуальное улучшение}
  • @ цитата [оригинальный автор] {возможно длинная цитата блока}

Это должно быть проанализированои переведены в различные выходные форматы (например, html и LaTeX).

У меня есть pyparsing грамматика, способная анализировать нетривиальные входные данные.

Проблема заключается в создании абзацев для HTML:

Какуказанный абзац заканчивается двойным переводом строки, но по существу начинается с конца предыдущего абзаца, если только некоторые элементы верхнего уровня (например: @chapter) не вмешиваются в разрыв последовательности.

Первая наивная попытка заключалась в накоплении фрагментов текста вглобальный буфер и выделять их в выбранных точках;эта логика работает логически, но, кажется, pyparsing вызывает это ParseActions несколько раз, поэтому мой глобальный буфер заканчивает тем, что содержит один и тот же фрагмент.

Я не нашел способа избежать такого дублирования илипометьте «начало абзаца» таким образом, чтобы я мог вернуться к нему позже, чтобы сгенерировать хорошо известный <p>Long line, maybe containing @speech{possibly nested with @standout{!} and other constructs}</p> (конечно, @standout должен отображаться на <b>!</b> и @speech на некоторый конкретный <div class="speech"></div>)

Какова «лучшая практика» для решения подобных проблем?

Примечание: генерация кода LaTeX гораздо менее проблематична, поскольку абзацы просто завершаются (как в разметке) либо с пустымлиния или с \par.

1 Ответ

0 голосов
/ 26 мая 2019

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

Я думаю, nestedExpr может быть способом для вас читать вперед до следующей полной разметки, а затем выполнить действие синтаксического анализа для повторного анализа содержимого для обработки любых вложенных директив разметки. nestedExpr возвращает его проанализированный ввод как вложенный список, но чтобы получить все в виде сплющенной строки, оберните его в originalTextFor.

Вот переделка примера simpleWiki.py из примеров pyparsing:

import pyparsing as pp

wiki_markup = pp.Forward()

# a method that will construct and return a parse action that will
# do the proper wrapping in opening and closing HTML, and recursively call 
# wiki_markup.transformString on the markup body text
def convert_markup_to_html(opening,closing):
    def conversionParseAction(s, l, t):
        return opening + wiki_markup.transformString(t[1][1:-1]) + closing
    return conversionParseAction

# use a nestedExpr with originalTextFor to parse nested braces, but return the 
# parsed text as a single string containing the outermost nested braces instead
# of a nested list of parsed tokens
markup_body = pp.originalTextFor(pp.nestedExpr('{', '}'))
italicized = ('ital' + markup_body).setParseAction(convert_markup_to_html("<I>", "</I>"))
bolded = ('bold' + markup_body).setParseAction(convert_markup_to_html("<B>", "</B>"))

# another markup and parse action to parse links - again using transform string
# to recursively parse any markup in the link text
def convert_link_to_html(s, l, t):
    t['link_text'] = wiki_markup.transformString(t['link_text'])
    return '<A href="{url}">{link_text}</A>'.format_map(t)
urlRef = ('link' 
          + '{' + pp.SkipTo('->')('link_text') + '->' + pp.SkipTo('}')('url') + '}'
          ).setParseAction(convert_link_to_html)

# now inject all the markup bits as possible markup expressions
wiki_markup <<= urlRef | italicized | bolded

Попробуйте!

wiki_input = """
Here is a simple Wiki input:

  ital{This is in italics}.
  bold{This is in bold}!
  bold{This is in ital{bold italics}! But this is just bold.}
  Here's a URL to link{Pyparsing's bold{Wiki Page}!->https://github.com/pyparsing/pyparsing/wiki}
"""
print(wiki_markup.transformString(wiki_input))

Печать:

Here is a simple Wiki input:

  <I>This is in italics</I>.
  <B>This is in bold</B>!
  <B>This is in <I>bold italics</I>! But this is just bold.</B>
  Here's a URL to <A href="https://github.com/pyparsing/pyparsing/wiki">Pyparsing's <B>Wiki Page</B>!</A>

Учитывая ваши примеры разметки, я думаю, что этот подход может продвинуть вас дальше.

...