Каков наилучший способ захвата неоднозначных сегментов текста?
Как лучше всего захватить внутренний текст в следующем случае?
inner_text = any*;
tag_cdata = '<![CDATA[' inner_text >cdata_start %cdata_end ']]>';
Проблема, кажется, cdata_end
действие запускается несколько раз из-за того, что inner_text может совпадать ]
,
1 ответ
Я нашел решение. Вы должны справиться с недетерминизмом. Первоначально не было понятно, но правильное решение выглядит примерно так:
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
встречаются, а не в самой длинной подпоследовательности. Эта неоднозначность, в некоторых случаях, может быть решена, используя самую длинную пару звезд **
, Что он делает, так это предпочитает соответствовать существующему шаблону, а не обтеканию.
Что меня удивило, так это то, что это также меняет способ вызова событий. Например, это создает машину, которая не может буферизовать более одного символа за раз при вызове обратных вызовов:
%%{
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')**;
}%%
который производит: