Ragel funktioniert gut. Sie müssen nur vorsichtig sein, was Sie suchen. Ihre Frage verwendet beide [[tag]]
und {{tag}}
, aber Ihr Beispiel verwendet [[tag]]
, also ich denke, das ist, was Sie als besonders behandeln möchten.
Was Sie tun möchten, ist essen Text, bis Sie eine offene Klammer treffen. Wenn dieser Klammer eine andere Klammer folgt, dann ist es an der Zeit, Kleinbuchstaben zu essen, bis Sie eine enge Klammer treffen. Da der Text im Tag keine Klammer enthalten kann, wissen Sie, dass das einzige Nicht-Fehlerzeichen, das dieser Klammer folgt, eine andere Klammer ist. An diesem Punkt bist du wieder da, wo du angefangen hast.
Nun, das ist eine wortgetreue Beschreibung dieser Maschine:
tag = '[[' lower+ ']]';
main := (
(any - '[')* # eat text
('[' ^'[' | tag) # try to eat a tag
)*;
Der schwierige Teil ist, wo rufen Sie Ihre Aktionen? Ich behaupte nicht, die beste Antwort darauf haben, aber hier ist, was ich kam mit:
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);
}%%
Es gibt ein paar nicht-offensichtliche Dinge:
- Die
eof
Aktion ist erforderlich, weil %PrintTextNode
wird immer nur beim Verlassen einer Maschine aufgerufen. Wenn die Eingabe mit normalem Text endet, gibt es keine Eingabe, um diesen Status zu verlassen. Da es auch aufgerufen wird, wenn die Eingabe mit einem Tag endet und kein endgültiger unbedruckter Textknoten vorhanden ist, testet PrintTextNode
, ob Text vorhanden ist.
- Die
%PrintTextNode
Aktion eingebettet in nach dem ^'['
, weil erforderlich, obwohl wir den Anfang markiert, wenn wir die [
getroffen, nachdem wir eine nicht [
treffen, werden wir versuchen, beginnen wieder etwas zu analysieren und den Startpunkt bemerken. Wir müssen diese beiden Zeichen löschen, bevor dies geschieht, daher dieser Aktionsaufruf.
Der vollständige Parser folgt.Ich habe es in C, weil das ist, was ich weiß, aber man sollte es wiederum in der Lage sein, welche Sprache Sie ziemlich leicht benötigen:
/* 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;
}
Hier einiger Testeingang:
[[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]]
Und hier ist der Ausgang aus dem Parser:
Der letzte Textknoten enthält nur den Zeilenumbruch am Ende der Datei.