Почему m /$./ m дает мне неожиданное поведение? - PullRequest
0 голосов
/ 04 декабря 2009

В Каким регулярным выражениям никогда не соответствовать? /$./ было дано в качестве ответа. Я немного поиграл с этим и обнаружил, что следующие две строки кода генерируют различный вывод. Второе совпадение, а первое нет. Кто-нибудь может объяснить, почему?

$ printf 'a\nb\n' | perl -0777 -ne 'print if m/$./m'
$ perl -0777 -e '$_="a\nb\n"; print if m/$./m'

Также обратите внимание, что добавление <> в следующих случаях приводит к сбою сопоставления:

$ printf 'a\nb\n' | perl -0777 -e '$b = "a\nb\n"; say $b =~ m/$./m'
$ printf 'a\nb\n' | perl -0777 -e '$b = "a\nb\n"; <>; say $b =~ m/$./m'

(то есть первый печатает «1», второй печатает пустую строку)

Ответы [ 4 ]

9 голосов
/ 04 декабря 2009

Включение предупреждений дает подсказку о причине:

$ printf 'a\nb\n' | perl -0777 -w -e 'use feature qw/say/; $b = "a\nb\n"; say $b =~ m/$./m'
Use of uninitialized value $. in regexp compilation at -e line 1.
1

Вы используете неопределенное значение в регулярном выражении. Последовательность $. относится к специальной переменной для номера строки последнего доступного дескриптора файла . не обозначает регулярное выражение для "конца строки, за которым следует любой символ". Поскольку вы не обращались ни к каким файлам, он все еще не определен, поэтому регулярное выражение пусто. Когда вы используете опцию -n, она эффективно оборачивает остальную часть программы в while (<>) { ... }, поэтому вы читаете <> и в итоге получаете 1 в $., потому что вы прочитали одну строку.

Когда вы говорите <> во второй попытке, вы получили доступ к дескриптору файла stdin. Теперь регулярное выражение m/1/m не соответствует входной строке.

6 голосов
/ 04 декабря 2009

Значение $. в вашем регулярном выражении анализируется как значение специальной переменной $. ($INPUT_LINE_NUMBER), а не как "конец строки, за которым следует любой символ".

Также обратите внимание, что модификатор /m изменяет значение $ с соответствия в конце строки на соответствие конца строки в любом месте строки. См. Модификаторы в perlre. Это означает, что после этого можно иметь что-то (с соответствующими модификаторами):

say "a\nb\n" =~ m/$ ./msx;

печатает "1". Модификатор /x разрешает использование встроенного пробела, поэтому мы можем отделить $ от ., чтобы избежать его интерпретации как переменной.

5 голосов
/ 04 декабря 2009

Этот код печатает для меня "сломанная труба", потому что Perl не ожидает здесь никакого ввода. Он также использует неопределенную переменную $. (вы увидите это, если добавите -w, переключитесь на perl). Эта переменная $. представляет текущий номер строки, затем читает строки на <...>. Вот почему он не определен в этом примере:

## matching pattern will look like m//m
printf 'a\nb\n' | perl -0777 -e '$b = "a\nb\n"; say $b =~ m/$./m'

Следующий код читает данные канала, но не будет совпадать, потому что $. стал равен 1 после <>. И соответствующий шаблон стал m/1/m:

## matching patter will be m/1/m, which is not found in $b value
printf 'a\nb\n' | perl -0777 -e '$b = "a\nb\n"; <>; say $b =~ m/$./m'

Обновление:

Используйте m'$.'m или m/$ ./mx (спасибо Майклу Карману), чтобы отключить переменную интерполяцию.

0 голосов
/ 04 декабря 2009

Во-первых, я считаю, что это из-за ключа -n. Другими словами

printf 'a\nb\n' | perl -0777 -ne 'print if m/$./m'

Заставляет $ _ получить значение a\n в первый раз в цикле и b\n во второй раз настолько ясно, что не будет совпадать. Принимая во внимание, что / m $ соответствует \ n во втором примере, поэтому это соответствует.

С последними двумя примерами я все еще работаю над этим:)

Редактировать: Ух ты, я был совершенно неправ, и я думаю, что у тебя тоже есть. Проблема в том, что m/$./m является не концом строки, за которым следует подстановочный знак, а скорее переменная $. интерполируется как регулярное выражение. Хлоп!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...