Ragel工作正常。你只需要小心你的配對。你的問題同時使用[[tag]]
和{{tag}}
,但你的例子使用[[tag]]
,所以我想這就是你想要特別處理的。
你想要做的是吃文字,直到你打開括號。如果該括號後面跟着另一個括號,那麼是時候開始吃小寫字母,直到你打開一個括號。由於標籤中的文本不能包含任何括號,因此您知道可以在該括號後面的唯一非錯誤字符是另一個右括號。那時,你回到了你開始的地方。
嗯,這是本機的一逐字描述:
tag = '[[' lower+ ']]';
main := (
(any - '[')* # eat text
('[' ^'[' | tag) # try to eat a tag
)*;
棘手的部分是,你在哪裏打電話給你的行動?我不主張有最好的答案,但這裏是我想出了:
static char *text_start;
%%{
machine parser;
action MarkStart { text_start = fpc; }
action PrintTextNode {
int text_len = fpc - text_start;
if (text_len > 0) {
printf("TEXT(%.*s)\n", text_len, text_start);
}
}
action PrintTagNode {
int text_len = fpc - text_start - 1; /* drop closing bracket */
printf("TAG(%.*s)\n", text_len, text_start);
}
tag = '[[' (lower+ >MarkStart) ']]' @PrintTagNode;
main := (
(any - '[')* >MarkStart %PrintTextNode
('[' ^'[' %PrintTextNode | tag) >MarkStart
)* @eof(PrintTextNode);
}%%
有一些不明顯的事情:
- 需要的
eof
行動,因爲%PrintTextNode
只有在離開機器時才被調用。如果輸入以普通文本結束,則不會有輸入使其離開該狀態。因爲當輸入以標籤結束時也會調用它,並且沒有最終的未打印文本節點,所以PrintTextNode
測試它有一些要打印的文本。
- 是因爲需要
^'['
後依偎在%PrintTextNode
行動,雖然我們打上一開始的時候我們打的[
,我們打非[
後,我們就開始嘗試再次解析任何東西,此話起點。我們需要在發生這種情況之前刷新這兩個字符,從而調用該動作。
完整的解析器如下。我這樣做是在C,因爲這就是我知道,但你應該能夠把它變成任何一種語言,你需要很容易:
/* ragel so_tag.rl && gcc so_tag.c -o so_tag */
#include <stdio.h>
#include <string.h>
static char *text_start;
%%{
machine parser;
action MarkStart { text_start = fpc; }
action PrintTextNode {
int text_len = fpc - text_start;
if (text_len > 0) {
printf("TEXT(%.*s)\n", text_len, text_start);
}
}
action PrintTagNode {
int text_len = fpc - text_start - 1; /* drop closing bracket */
printf("TAG(%.*s)\n", text_len, text_start);
}
tag = '[[' (lower+ >MarkStart) ']]' @PrintTagNode;
main := (
(any - '[')* >MarkStart %PrintTextNode
('[' ^'[' %PrintTextNode | tag) >MarkStart
)* @eof(PrintTextNode);
}%%
%% write data;
int
main(void) {
char buffer[4096];
int cs;
char *p = NULL;
char *pe = NULL;
char *eof = NULL;
%% write init;
do {
size_t nread = fread(buffer, 1, sizeof(buffer), stdin);
p = buffer;
pe = p + nread;
if (nread < sizeof(buffer) && feof(stdin)) eof = pe;
%% write exec;
if (eof || cs == %%{ write error; }%%) break;
} while (1);
return 0;
}
這裏的一些測試輸入:
[[header]]
<html>
<head><title>title</title></head>
<body>
<h1>[[headertext]]</h1>
<p>I am feeling very [[emotion]].</p>
<p>I like brackets: [ is cool. ] is cool. [] are cool. But [[tag]] is special.</p>
</body>
</html>
[[footer]]
而這裏的輸出來自解析器:
TAG(header)
TEXT(
<html>
<head><title>title</title></head>
<body>
<h1>)
TAG(headertext)
TEXT(</h1>
<p>I am feeling very)
TAG(emotion)
TEXT(.</p>
<p>I like brackets:)
TEXT([)
TEXT(is cool. ] is cool.)
TEXT([])
TEXT(are cool. But)
TAG(tag)
TEXT(is special.</p>
</body>
</html>
)
TAG(footer)
TEXT(
)
最終文本節點僅包含文件末尾的換行符。