TLDR: Проблема в том, что тестовая строка ввода с Start Invoice Details
заканчивается горизонтальным пробелом, с которым вы не имеете дела.
Два способа справиться с этим (кроме изменения ввода)
# Explicitly: vvv
token invoice-prelude-end { <line> <?before 'Start Invoice Details' \h* \n>}
# Implicitly:
rule invoice-prelude-end { <line><?before 'Start Invoice Details' \n>}
# ^ must be a rule and there must be a space ^
# (uses the fact that you wrote your own <ws> token)
Ниже приведены некоторые вещи, которые, я думаю, будут полезны
Я бы использовал «разделенный» функцией %
в line
и super-phrase
token super-phrase { <super-word>+ % \h } # single % doesn't capture trailing separator
token line {
^^ \h*
<super-word>* %% \h+ # double %% can capture optional trailing separator
\n
}
Это [почти] точно соответствует тому, что вы написали.
(То, что вы написали, должно не совпадать с <super-word>
дважды в <line>
, но это должно произойти только один раз.)
Я бы использовал функцию объемного звучания ~
в invoice-prelude
token invoice-prelude {
# zero or more <line>s surrounded by <invoice-prelude-start> and <invoice-prelude-end>
<invoice-prelude-start> ~ <invoice-prelude-end> <line>*?
<line> # I assume this is here for debugging
}
Обратите внимание, что на самом деле он ничего не получил, будучи rule
, потому что весь горизонтальный пробел уже обработан остальной частью кода.
Я не думаю, что последняя строка прелюдии счета-фактуры является особенной, поэтому удалите <line>
из invoice-prelude-end
.
(<line>*?
в invoice-prelude
захватит его вместо этого.)
token invoice-prelude-end {<?before 'Start Invoice Details' \h* \n>}
Единственное регулярное выражение, которое может быть полезным для rule
- это invoice-prelude-start
и invoice-prelude-end
.
rule invoice-prelude-start {^^ Invoice Summary \n}
# `^^` is needed so the space ^ will match <.ws>
rule invoice-prelude-end {<?before ^^ Start Invoice Details $$>}
Это сработало бы, только если у вас все в порядке с чем-то вроде Invoice Summary 
.
Обратите внимание, что invoice-prelude-start
необходимо использовать \n
для захвата, но invoice-prelude-end
может использовать $$
вместо этого, потому что он все равно не захватывает \n
.
Если вы измените super-word
на что-то отличное от \S+
, тогда вы также можете изменить ws
на что-то вроде \h+ | <.wb>
. (граница слова)
#! /usr/bin/env perl6
use v6.d;
grammar invoice {
token TOP { # testing
<invoice-prelude>
<line>
}
token ws { \h* | <.wb> };
token super-word { \S+ };
token super-phrase { <super-word>+ % \h }
token line {
^^ \h*
<super-word>* %% \h+
\n
};
rule invoice-prelude-start {^^ Invoice Summary \n}
rule invoice-prelude-end {<?before ^^ Start Invoice Details $$>};
token invoice-prelude {
<invoice-prelude-start> ~ <invoice-prelude-end>
<line>*?
}
}
multi sub MAIN(){
my $t = q :to/EOQ/;
Invoice Summary
asd fasdf
asdfasdf
asd 123-fasdf $1234.00
qwe {rq} [we-r_q] we
Start Invoice Details
EOQ
say $t;
say invoice.parse($t);
}