在以下情况下捕获内部文本的最佳方法是什么?
inner_text = any*;
tag_cdata = '<![CDATA[' inner_text >cdata_start %cdata_end ']]>';
问题是,由于 inner_text 可以 match ,该动作似乎cdata_end
触发了多次]
。
在以下情况下捕获内部文本的最佳方法是什么?
inner_text = any*;
tag_cdata = '<![CDATA[' inner_text >cdata_start %cdata_end ']]>';
问题是,由于 inner_text 可以 match ,该动作似乎cdata_end
触发了多次]
。
我找到了解决方案。你需要处理非确定性。最初并不清楚,但正确的解决方案是这样的:
inner_text = any*;
tag_cdata = '<![CDATA[' inner_text >text_begin %text_end ']]>' %cdata_end;
action text_begin {
text_begin_at = p;
}
action text_end {
text_end_at = p;
}
action cdata_end {
delegate.cdata(data.byteslice(text_begin_at, text_end_at-text_begin_at))
}
本质上,您要等到确定解析了完整的 CDATA 标记后再触发回调,使用之前捕获的信息。
此外,我发现 Ragel 中某些形式的非确定性需要使用优先级来明确处理。虽然这看起来有点难看,但在某些情况下它是唯一的解决方案。
在处理诸如此类的模式时,(a+ >a_begin %a_end | b)*
您会发现每个a
遇到的事件都会被调用,而不是在最长的子序列中调用。在某些情况下,这种模糊性可以使用最长匹配 kleene star 来解决**
。这样做是它更喜欢匹配现有模式而不是环绕。
令我惊讶的是,这实际上也修改了事件的调用方式。例如,这会产生一台在调用回调时无法一次缓冲多个字符的机器:
%%{
machine example;
action a_begin {}
action a_end {}
main := ('a'+ >a_begin %a_end | 'b')*;
}%%
产生:
你会注意到它a_begin
每次a_end
都会调用。
相比之下,我们可以使内部循环和事件处理变得贪婪:
%%{
machine example;
action a_begin {}
action a_end {}
main := ('a'+ >a_begin %a_end | 'b')**;
}%%
产生: