Perl6 интерполирует массив в соответствии для функций И, ИЛИ, НЕ
Я пытаюсь заново выполнить мою программу для сопоставления всех, сопоставления с любым, сопоставления ни с одним из элементов в массиве. Некоторые из документации по Perl6 не объясняют поведение текущей реализации (Rakudo 2018.04), и у меня есть еще несколько вопросов.
(1) В документации по регулярному выражению сказано, что интерполяция массива в регулярное выражение совпадения означает "самое длинное совпадение"; однако этот код, похоже, не делает этого:
> my $a="123 ab 4567 cde";
123 ab 4567 cde
> my @b=<23 b cd 567>;
[23 b cd 567]
> say (||@b).WHAT
(Slip)
> say $a ~~ m/ @b /
「23」 # <=== I expected the match to be "567" (@b[3] matching $a) which is longer than "23";
(2) (|| @b) - скольжение; Как я могу легко сделать ИЛИ или И всех элементов в массиве без явного цикла по массиву?
> say $a ~~ m:g/ @b /
(「23」 「b」 「567」 「cd」)
> say $a ~~ m:g/ ||@b /
(「23」 「b」 「567」 「cd」)
> say $a ~~ m/ ||@b /
「23」
> say $a ~~ m:g/ |@b /
(「23」 「b」 「567」 「cd」)
> say $a ~~ m:g/ &@b /
(「23」 「b」 「567」 「cd」)
> say $a ~~ m/ &@b /
「23」
> say $a ~~ m/ &&@b /
「23」 # <=== && and & don't do the AND function
(3) То, что я закончил, - это сжатие моих предыдущих кодов в 2 строки:
my $choose = &any; # can prompt for choice of any, one, all, none here;
say so (gather { for @b -> $z { take $a ~~ m/ { say "==>$_ -->$z"; } <{$z}> /; } }).$choose;
вывод "True", как и ожидалось. Но я надеюсь, что более простой путь, без цикла "собери-возьми" и "за".
Большое спасибо за любые идеи.
lisprog
2 ответа
интерполировать массив в соответствии для функций AND, OR, NOT
Я не знаю лучшего решения, чем Мориц для AND
,
Я покрываю OR
ниже.
Один естественный способ написать NOT
из списка токенов совпадения можно было бы использовать отрицательные версии предпросмотра или утверждения с задним взглядом, например:
my $a="123 ab 4567 cde";
my @b=<23 b cd 567>;
say $_>>.pos given $a ~~ m:g/ <!before @b> /;
дисплеи:
(0 2 3 4 6 7 9 10 11 13 14 15)
что позиции 12 матчей не 23
, b
, cd
, или же 567
в строке "123 ab 4567 cde"
показано линией ^
s ниже которого указывают на каждую из соответствующих позиций символов:
my $a="123 ab 4567 cde";
^ ^^^ ^^ ^^^ ^^^
0123456789012345
Я пытаюсь заново выполнить мою программу для сопоставления всех, сопоставления с любым, сопоставления ни с одним из элементов в массиве.
Эти звуковые соединения, как и некоторые другие вопросы, явно касаются соединений. Если вы подключились к своей существующей программе, мне / другим будет легче увидеть, что вы пытаетесь сделать.
(1)
||@b
соответствует крайнему левому совпадающему токену в @b
не самый длинный.
Написать |@b
с одним |
, чтобы найти самый длинный соответствующий токен в @b
, Или, еще лучше, просто напишите @b
, что является сокращением для того же самого.
Оба из этих образцов соответствия (|@b
или же ||@b
), как и любые другие шаблоны сопоставления, зависят от того, как работает механизм регулярных выражений, как кратко описано Морицем и более подробно ниже.
Когда механизм регулярных выражений сопоставляет регулярное выражение с входной строкой, он запускается в начале регулярного выражения и в начале входной строки.
Если он не совпадает, он проходит мимо первого символа во входной строке, отказываясь от этого символа, и вместо этого делает вид, что входная строка началась со второго символа. Затем он снова пытается сопоставить, начиная с начала регулярного выражения, но второй символ входной строки. Это повторяется до тех пор, пока не достигнет конца строки или не найдет совпадение.
Учитывая ваш пример, двигатель не соответствует прямо в начале 123 ab 4567 cde
но успешно совпадает 23
начиная со второй позиции символа. Итак, это сделано - и 567
в вашем матче шаблон не имеет значения.
Один из способов получить ожидаемый ответ:
my $a="123 ab 4567 cde";
my @b=<23 b cd 567>;
my $longest-overall = '';
sub update-longest-overall ($latest) {
if $latest.chars > $longest-overall.chars {
$longest-overall = $latest
}
}
$a ~~ m:g/ @b { update-longest-overall( $/ ) } /;
say $longest-overall;
дисплеи:
「567」
Использование :g
объясняется ниже.
(2)
|@b
или же ||@b
в основном коде означают что-то совершенно не связанное с тем, что они означают внутри регулярного выражения. Как вы видете, |@b
такой же как @b.Slip
, ||@b
средства @b.Slip.Slip
который оценивает @b.Slip
,
Чтобы сделать "параллельные" Longest-Match-Pattern-Wins OR
из элементов @b
, записывать @b
(или же |@b
) внутри регулярного выражения
Чтобы сделать "последовательный" крайний левый-матч-шаблон-побед OR
из элементов @b
, записывать ||@b
внутри регулярного выражения
Я до сих пор не мог понять, что &
а также &&
делать, когда используется для префикса массива в регулярном выражении. Мне кажется, что есть несколько ошибок, связанных с их использованием.
В некотором коде в вашем вопросе вы указали :g
наречие. Это заставляет движок не останавливаться, когда он находит совпадение, а просто проходить мимо подстроки, с которой он только что совпал, и начинать попытки снова сопоставить дальше во входной строке.
(Есть и другие наречия. :ex
наречие самое экстремальное. В этом случае, когда в заданной позиции во входной строке есть совпадение, движок пытается сопоставить любой другой шаблон совпадения в той же позиции в регулярном выражении и входной строке. Он продолжает делать это независимо от того, сколько совпадений он накопил, пока не попробует каждое последнее возможное совпадение в этой позиции в регулярном выражении и входной строке. Только когда все эти возможности исчерпаны, он перемещается на один символ вперед во входной строке и пытается исчерпывающе сопоставить все заново.)
(3)
Мой лучший снимок:
my $a="123 ab 4567 cde";
my @b=<23 b cd 567>;
my &choose = &any;
say so choose do for @b -> $z {
$a ~~ / { say "==>$a -->$z"; } $z /
}
(1) В документации по регулярному выражению сказано, что интерполяция массива в регулярное выражение совпадения означает "самое длинное совпадение"; однако этот код, похоже, не делает этого:
Фактическое правило состоит в том, что регулярное выражение находит крайнее левое совпадение первым, а самое длинное совпадение - вторым.
Тем не менее, крайнее левое правило верно для всех совпадений регулярных выражений, поэтому в документации регулярных выражений не упоминается об этом явно, когда речь идет об альтернативах.
(2) (|| @b) - скольжение; Как я могу легко сделать ИЛИ или И всех элементов в массиве без явного цикла по массиву?
Вы всегда можете сначала создать регулярное выражение в виде текста:
my $re_text = join '&&', @branches;
my $regex = re/ <$re_text> /;