我有一个bbcode - > html转换器响应textarea中的change事件。目前,这是使用一系列正则表达式完成的,并且存在许多病理情况。我一直想在这个语法上磨铅笔,但不想进入牦牛剃须。但是......最近我开始意识到pegjs,这似乎是PEG解析器生成的完全实现。我已经指定了大部分语法,但现在我想知道这是否适合使用完整的解析器。
我的具体问题是:
由于我的应用程序依赖于将我能够转换为HTML并将其余内容保留为原始文本,使用可能因语法错误而失败的解析器实现bbcode是否有意义?例如:一旦输入关闭标记的结束括号,肯定会预期[url=/foo/bar]click me![/url]
成功。但是在此期间用户会看到什么?使用正则表达式,我可以忽略不匹配的东西,并将其视为普通文本以用于预览目的。使用正式语法,我不知道这是否可行,因为我依赖于从解析树创建HTML以及解析失败的原因是什么?
我不清楚应该在哪里进行转换。在正式的基于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 :(得分: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。免责声明:这是我的答案。
答案 1 :(得分:2)
关于你的第一个问题,我认为现场预览会很困难。您指出的解析器无法理解输入是“正在进行中”的问题是正确的。 Peg.js会告诉你错误发生在哪一点,所以也许你可以拿出那些信息然后再说一遍并再次解析,或者如果缺少结束标记,请尝试在最后添加它。
你问题的第二部分比较容易,但之后你的语法看起来不那么好。基本上你所做的就是在每条规则上加上回调,例如
text
= text:non_tag+ {
// we captured the text in an array and can manipulate it now
return text.join("");
}
目前你必须在语法中内联编写这些回调。我现在正在做很多这样的工作,所以我可以向peg.js做一个pullrequest来解决这个问题。但我不确定我什么时候能找到这个。
答案 2 :(得分:1)
尝试类似此替换规则的内容。你走在正确的轨道上;你只需告诉它汇总结果。
文本 = result:non_tag + {return result.join(''); }