首页 > 解决方案 > 如何在流中标记 pyparsing 位置以便稍后返回?

问题描述

背景:

我正在尝试实现一种用于写小说的简单(?)标记语言。

这与通常的标记完全不同,因为语义以不同的原语为中心,特别是直接语音与列表相去甚远。

基本结构是众所周知的:@part{title}@chapter{title}并且@scene[{title}]具有通常的含义,并且 double-\n表示分节符。

具体功能包括:

这应该被解析并翻译成不同的输出格式(例如: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.

标签: htmlmarkuppyparsing

解决方案


您是否有可能将其改写为“稍后再回到开头”的问题,而是将其改写为“在我需要了解整个事情的情况下提前阅读”的问题?

我认为nestedExpr这可能是一种让您提前阅读下一个完整标记的方法,然后通过解析操作重新解析内容以处理任何嵌套的标记指令。nestedExpr将其解析的输入作为嵌套列表返回,但要将所有内容作为扁平字符串获取,请将其包装在originalTextFor.

这是 pyparsing 示例中 simpleWiki.py 示例的返工:

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>

鉴于您的标记示例,我认为这种方法可能会让您走得更远。


推荐阅读