Вопрос о сопоставлении шаблона Perl с переменной

Я пытаюсь открыть файл, сопоставить определенную строку, а затем оборачивать HTML-теги вокруг этой строки. Кажется ужасно простым, но, видимо, я что-то упускаю и неправильно понимаю переменные сопоставленного шаблона Perl.

Я сопоставляю строку с этим:

$line =~ m/(Number of items:.*)/i;

Что помещает всю строку в $1. Затем я пытаюсь распечатать свою новую строку следующим образом:

print "<p>" . $1 . "<\/p>;

Я ожидаю, что он напечатает это:

<p>Number of items: 22</p>

Однако на самом деле я получаю следующее:

</p>umber of items: 22

Я пробовал всевозможные варианты - вывод каждого бита на отдельной строке, установка $1 в новую переменную, использование $+ и $& и т. д., и я всегда получаю один и тот же результат.

Что мне не хватает?


person jeff    schedule 05.01.2011    source источник
comment
То, что вы описали, работает на моей машине. Можете ли вы опубликовать фактический код, который вы используете?   -  person Anon.    schedule 06.01.2011
comment
Пожалуйста, включите полный (но минимальный) код, который вы используете.   -  person JB.    schedule 06.01.2011


Ответы (3)


У вас есть \r в вашем совпадении, что при печати приводит к искаженному выводу.

редактировать: Чтобы объяснить больше, скорее всего, ваш файл имеет окончание строки \r\n в стиле Windows. chomp не удалит \r, который затем попадет в ваше жадное совпадение и приведет к неприятному результату (\r означает вернуться к началу строки и продолжить печать).

Вы можете удалить \r, добавив что-то вроде

$line =~ tr/\015//d;
person ivancho    schedule 05.01.2011
comment
Это хорошее предположение, учитывая заявленное поведение. Педантичность/пояснение: chomp не удалит \r по умолчанию, но может, если вы измените $/. Обычно в этом нет необходимости, поскольку слой perlio будет преобразовывать новые строки платформы в логические во время ввода/вывода. Предостережение заключается в том, что перевод не работает, если формат файла не соответствует платформе (например, обработка файла с новыми строками в стиле Windows на платформе * nix). - person Michael Carman; 06.01.2011
comment
Кажется, это проблема - я использую Cygwin и читаю текстовый файл Windows. Я жевал строки, но, очевидно, не получал \r. Это никогда не было проблемой ни с чем, что я делал раньше, и способ замены текста не заставил меня задуматься об этом. Теперь я явно заменяю \r, и он отлично работает. Спасибо! - person jeff; 06.01.2011

Можете ли вы предоставить полный фрагмент кода, демонстрирующий вашу проблему? Я этого не вижу.

Следует быть осторожным с тем, что $1 и друзья ссылаются на захваты из последнего успешного совпадения в этой динамической области. Вы всегда должны убедиться, что совпадение успешно, прежде чем использовать его:

$line = "Foo Number of items: 97\n";
if ( $line =~ m/(Number of items:.*)/i ) {
    print "<p>" . $1 . "<\/p>\n";
}
person ysth    schedule 05.01.2011
comment
Действительно хороший момент. Меня укусил $1 и т. д., оставшийся после предыдущего матча. - person justintime; 06.01.2011

Вы только что узнали (на будущее), насколько опасным может быть .*.

Ударившись головой о подобные неприятности, в эти дни я предпочитаю быть как можно более точным в том, что я ожидаю запечатлеть. Может быть

$line =~ m/(Number of items:\s+\d+)/;

Тогда я уверен, что в первую очередь не поймаю оскорбительного управляющего персонажа. Что бы Cygwin ни делал с файлами Windows, я могу оставаться в блаженном неведении.

person Narveson    schedule 05.01.2011