Я пытаюсь написать токенизатор для Усы на Perl. Я легко справлюсь с большинством токенов следующим образом:
#!/usr/bin/perl
use strict;
use warnings;
my $comment = qr/ \G \{\{ ! (?<comment> .+? ) }} /xs;
my $variable = qr/ \G \{\{ (?<variable> .+? ) }} /xs;
my $text = qr/ \G (?<text> .+? ) (?= \{\{ | \z ) /xs;
my $tokens = qr/ $comment | $variable | $text /x;
my $s = do { local $/; <DATA> };
while ($s =~ /$tokens/g) {
my ($type) = keys %+;
(my $contents = $+{$type}) =~ s/\n/\\n/;
print "type [$type] contents [$contents]\n";
}
__DATA__
{{!this is a comment}}
Hi {{name}}, I like {{thing}}.
Но у меня проблемы с директивой Set Delimiters:
#!/usr/bin/perl
use strict;
use warnings;
my $delimiters = qr/ \G \{\{ (?<start> .+? ) = [ ] = (?<end> .+?) }} /xs;
my $comment = qr/ \G \{\{ ! (?<comment> .+? ) }} /xs;
my $variable = qr/ \G \{\{ (?<variable> .+? ) }} /xs;
my $text = qr/ \G (?<text> .+? ) (?= \{\{ | \z ) /xs;
my $tokens = qr/ $comment | $delimiters | $variable | $text /x;
my $s = do { local $/; <DATA> };
while ($s =~ /$tokens/g) {
for my $type (keys %+) {
(my $contents = $+{$type}) =~ s/\n/\\n/;
print "type [$type] contents [$contents]\n";
}
}
__DATA__
{{!this is a comment}}
Hi {{name}}, I like {{thing}}.
{{(= =)}}
Если я поменяю его на
my $delimiters = qr/ \G \{\{ (?<start> [^{]+? ) = [ ] = (?<end> .+?) }} /xs;
Работает нормально, но смысл директивы Set Delimiters состоит в том, чтобы изменить разделители, поэтому код будет выглядеть как
my $variable = qr/ \G $start (?<variable> .+? ) $end /xs;
И совершенно справедливо сказать {{{== ==}}}
(т.е. изменить разделители на {=
и =}
). То, что я хочу, но, возможно, не то, что мне нужно, это способность сказать что-то вроде (?:not starting string)+?
. Я полагаю, что мне просто придется отказаться от чистоты и добавить код в регулярное выражение, чтобы заставить его соответствовать только тому, что я хочу. Я пытаюсь избежать этого по четырем причинам:
- Я не думаю, что это очень чисто.
- Помечено как экспериментальное.
- Я не очень знаком с ним (думаю, что доходит до
(?{CODE})
и возвращает специальные значения.
- Я надеюсь, что кто-то знает какую-то другую экзотическую функцию, с которой я не знаком, которая лучше подходит к ситуации (например,
(?(condition)yes-pattern|no-pattern)
).
Просто чтобы прояснить ситуацию (я надеюсь), я пытаюсь сопоставить начальный разделитель постоянной длины, за которым следует самая короткая строка, которая допускает совпадение и не содержит начального разделителя, за которым следует пробел, за которым следует знак равенства, за которым следует самая короткая строка, которая допускает совпадение, заканчивающееся конечным разделителем.