Как я могу перевести это регулярное выражение Perl5/PCRE в Perl 6?

Просто чтобы избавиться от этого, я использовал бы index, substr или подобные, поскольку они являются очевидным решением для моего конкретного случая, но я делаю grammar и поэтому могу использовать только regex. :(

При этом совет по переводу регулярных выражений Perl5/PCRE в регулярные выражения Perl6 в любом случае является хорошим содержанием SO, потому что Perl 6 набирает популярность, а его механизм регулярных выражений сильно отличается.


Вот регулярное выражение, которое соответствует только строке, которая не содержит ни одного из заданного списка символов.
(попробуйте здесь.)

^(?:(?!\/).)*$
^            # assert position at start of string
(?:          # begin a noncapturing group 
   (?!       # negative lookahead: following regex must not match the string
      \/     # literal forward slash
    )        # end negative lookahead
    .        # any character, once
 )*          # the previous noncapturing group, 0..Inf times
 $           # assert position at end of string

Очевидно, не работает в Perl 6 по ряду причин.

По указанной выше причине я хотел бы использовать это в Perl 6. Вот то, во что я пытался перевести это, основываясь на CTRL-F ing документы по регулярным выражениям perl6 для non capturing и negative lookahead:

[ \/ <!before .*> \/ <!after .*> || .? ]*

И разбивка (думаю?):

[       # begin a noncapturing group which apparently look like a charclass in p6
\/      # a literal forward slash  
<!before .*> # negative lookahead for the immediately preceding regex (literal /)
\/      # a literal /
<!after .*>  # negative lookbehind for the immediately preceding regex
|| .?   # force this to be a noncapturing group, not a charclass
]*      # end noncapturing group and allow it to match 0..Inf times

Я реализую это как my regex not-in { ... }, а затем использую как /^<not-in>$/. Однако он возвращает Nil для каждой строки, что означает, что он работает неправильно.

Мне не удалось найти эквивалент http://regex101.com для Perl 6, так что поэкспериментируйте с это не так просто, как было бы с Perl 5.

Как мне перевести это на Perl 6?


person cat    schedule 27.01.2016    source источник
comment
@ChristopherBottoms Да, но я понятия не имею, какое отношение это имеет к чему-либо   -  person cat    schedule 28.01.2016
comment
/^not-in$/ должно быть /^<not-in>$/.   -  person CIAvash    schedule 28.01.2016
comment
@CIAvash Конечно, должен! Я устал, извини.   -  person cat    schedule 28.01.2016
comment
Вам могут понравиться Grammar::Tracer и Grammar::Debugger (оба доступны после установки Grammar::Debugger, если вы не они уже есть). Они очень помогли мне, когда я отлаживал свои грамматики.   -  person Christopher Bottoms    schedule 28.01.2016
comment
Я думаю, было бы лучше даже в Perl 5, если бы вы просто перевернули свою проверку "a" !~ m{/} в Perl 5 и "a" !~~ m{'/'} в Perl 6. Хотя я могу представить несколько случаев, когда вам нужно знать, как написать что-то вроде вас. m{^ [^\/]* $}x было бы лучше, хотя в этом конкретном случае.   -  person Brad Gilbert    schedule 28.01.2016
comment
@BradGilbert, но вы можете использовать регулярное выражение только в классе компиляции регулярных выражений, что я отметил в начале вопроса. Если бы я мог иметь произвольный код в регулярном выражении, я бы использовал index или substr.   -  person cat    schedule 28.01.2016
comment
m{^ [^\/]* $}x все равно будет лучше   -  person Brad Gilbert    schedule 28.01.2016
comment
@BradGilbert Пожалуйста, добавьте свой "a" !~~ m{'/'} в качестве ответа. @cat Если Брэд Гилберт добавит это в качестве ответа, это должен быть принятый ответ.   -  person Christopher Bottoms    schedule 29.01.2016
comment
@ChristopherBottoms IIRC, принятый ответ — это тот, который был наиболее полезен для спрашивающего, а не обязательно правильный ответ. В то время как Брэд ответ может быть правильным, потому что я ограничен регулярным выражением, ваше на самом деле было наиболее полезным и, вероятно, останется принятым.   -  person cat    schedule 29.01.2016
comment
@кот Спасибо. Это интересно. Я все еще надеюсь, что он добавит свой ответ. Мне нравится его ответ больше, чем мой, нравится вам это или нет. :)   -  person Christopher Bottoms    schedule 29.01.2016


Ответы (3)


Краткий ответ

Регулярное выражение для сопоставления только строк, в которых отсутствует косая черта: /^ <-[ / ]>* $/

/ начало регулярного выражения
^ начало строки

<-[ открыть отрицательный класс символов (без - это был бы обычный класс символов)
/ символы, которым класс не будет соответствовать
]> закрыть класс символов

* ноль или более копий этого класса
$ конец строки
/ конец регулярного выражения

Пробелы в регулярных выражениях Perl 6 по умолчанию игнорируются.


Полный ответ

Если я правильно понимаю, вы просто пытаетесь сопоставить строку, не содержащую косую черту. В этом случае просто используйте отрицательный класс символов.

Класс символов, содержащий a и b, будет записан так: <[ab]>

Класс символов, содержащий что-либо кроме a или b, будет записан так: <-[ab]>

Класс символов, содержащий что-либо, кроме /, будет записан так: <-[ / ]>, а регулярное выражение для проверки того, что ни один символ в строке не содержит косую черту, будет /^ <-[ / ]>* $/.

Этот код соответствует, когда в строке отсутствует косая черта, и не соответствует, когда она содержит косую черту:

say "Match" if "abc/" ~~ /^ <-[ / ]>* $/; # Doesn't match
say "Match" if "abcd" ~~ /^ <-[ / ]>* $/; # Matches

Предпочтительным способом проверки исключения одного символа является использование функции index. Однако, если вы хотите исключить более одного символа, просто используйте класс отрицательных символов со всеми символами, которые вы не хотите находить в строке.

person Christopher Bottoms    schedule 27.01.2016
comment
Да, ваша интерпретация моего вопроса была правильной, извините. Я не видел в документах такого способа определения отрицательного прогноза, но спасибо! - person cat; 28.01.2016

буквальный перевод исходного регулярного выражения ^(?:(?!\/).)*$ в синтаксис Perl 6 выглядит следующим образом:

^ [ <!before \/> . ]* $

Это достаточно просто для прямого перевода.

  • Замените (?:...) на [...]
  • Замените (?!...) на <!before...>
  • Предположим, что модификатор x по умолчанию

Все остальное в этом примере остается прежним.

Я проверил это с помощью простого:

say "Match" if "ab/c" ~~ /^ [ <!before \/> . ]* $/; # doesn't match
say "Match" if "abc"  ~~ /^ [ <!before \/> . ]* $/; # Match
person Lucas Trzesniewski    schedule 27.01.2016
comment
Чуть более читабельно, без «синдрома наклоненной зубочистки»: ^ [ <!before '/'> . ]* $ - person mscha; 31.01.2016

Просто чтобы убрать это с пути

Ваш вопрос начинается с:

Просто чтобы избавиться от этого, я бы использовал index, substr или подобное, поскольку они являются очевидным решением для моего конкретного случая, но я создаю грамматику и поэтому могу использовать только регулярное выражение. :(

Будучи педантичным, вы можете это сделать. На самом деле вы можете вставлять произвольный код в регулярные выражения Perl.


Типичный пример Perl 6:

/ (\d**1..3) <?{ $/ < 256 }> / # match an octet

Бит \d**1..3 соответствует от 1 до 3 десятичных цифр. Скобки (...), окружающие этот бит, говорят Perl 6 сохранить совпадение в специальной переменной $ /.

Бит <?{ ... }> является подтверждением кода. Если код возвращает true, регулярное выражение продолжается. Если нет, он отступает или терпит неудачу.


Использование index и т. д. (в данном случае я выбрал substr-eq) внутри регулярного выражения громоздко и, вероятно, безумно. Но это выполнимо:

say "a/c" ~~ / a <?{ $/.orig.substr-eq: '/', $/.to }> . c /;
say "abc" ~~ / a <?{ $/.orig.substr-eq: '/', $/.to }> . c /

отображает:

「a/c」
Nil

(Вызов .orig для объекта Match возвращает исходную строку, которая была или находится в процессе сопоставления. Вызов .to возвращает индекс в этой исходной строке, до которого дошло или дошло совпадение; "abc" ~~ / a { say $/.orig, $/.to } bc / отображает abc1. )

person raiph    schedule 31.01.2016
comment
Спасибо, что научили меня чему-то! Когда я увидел этот ответ в своих уведомлениях, я ожидал, что меня пропустят за то, что я так начал свой вопрос :) - person cat; 01.02.2016
comment
Я не хочу подводить Одри или иметь Jackson Galaxy выследите меня. :) - person raiph; 01.02.2016
comment
Я просматривал некоторые свои старые вопросы, и я думаю, что никогда не нажимал на ссылки в ваших комментариях, но они были довольно забавными, особенно совпадение, что я также являюсь трансгендерной женщиной-разработчиком свободного программного обеспечения, и теперь Одри мой кумир :) - person cat; 28.09.2016
comment
:) Мне любопытно, слышали ли вы о флаге компилятора -Ofun? - person raiph; 28.09.2016
comment
Я упомянул Одри в своем январском комментарии, потому что я всегда думаю о любви и мудрости, которые лежат в основе ее представления об объятиях троллей, когда я пишу ответы незнакомцам в Интернете. (Не то чтобы вы были троллем, но что там еще.) Я упомянул принятие -Ofun в качестве руководящего принципа потому что это, пожалуй, самое важное влияние, которое она оказала на Perl 6. Если вы еще не посетили #perl6 или #perl6-dev а опытный -Офун на самом деле, ты многое упускаешь... ;) - person raiph; 29.09.2016