Разъяснение по чомп - PullRequest
       59

Разъяснение по чомп

7 голосов
/ 03 сентября 2011

Я сейчас на каникулах и решил потратить свое время на изучение Perl. Я работаю с Beginning Perl (http://www.perl.org/books/beginning-perl/) и заканчиваю упражнения в конце третьей главы.

В одном из упражнений я попросил меня «Хранить ваши важные номера телефонов в хэше. Напишите программу для поиска номеров по имени человека».

Во всяком случае, я придумал это:

#!/usr/bin/perl
use warnings;
use strict;

my %name_number=
(
Me => "XXX XXX XXXX",
Home => "YYY YYY YYYY",
Emergency => "ZZZ ZZZ ZZZZ",
Lookup => "411"
);

print "Enter the name of who you want to call (Me, Home, Emergency, Lookup)", "\n";
my $input = <STDIN>;
print "$input can be reached at $name_number{$input}\n";

И это просто не сработает. Я продолжал получать это сообщение об ошибке:

Использование неинициализированного значения в конкатенации (.) Или строки в hello.plx строка 17, строка 1

Я попытался немного поиграть с кодом, но каждое «решение» выглядело более сложным, чем «решение», которое было до него. Наконец я решил проверить ответы.

Единственная разница между моим кодом и ответом заключалась в наличии chomp ($input); после <STDIN>;.

Теперь автор использовал chomp в предыдущем примере, но на самом деле он не раскрыл то, что делал chomp. Итак, я нашел этот ответ на www.perlmeme.org:

Функция chomp() удалит (обычно) любой символ новой строки из конец строки. Обычно мы говорим, что на самом деле удаляет любой символ, который соответствует текущему значению $/ (вход разделитель записей), и $/ по умолчанию переводится на новую строку.


В любом случае, мои вопросы:

  1. Какие новые строки удаляются? Perl автоматически добавляет "\n" к входу из <STDIN>? Мне просто немного непонятно, потому что когда я читаю «он фактически удаляет любой символ, который соответствует текущему значению $/», я не могу удержаться от мысли, что «я не помню, чтобы где-то в моем коде было указано $/» . "

  2. Я бы хотел как можно скорее разработать лучшие практики - лучше ли всегда включать chomp после <STDIN> или есть сценарии, где это не нужно?

Ответы [ 5 ]

9 голосов
/ 03 сентября 2011

<STDIN> читает до конца входной строки, которая содержит символ новой строки, если вы нажмете клавишу возврата, чтобы ввести ее, что вы, вероятно, делаете.

chomp удаляет символ новой строки в конце строки,$/ - это переменная (как вы обнаружили, по умолчанию переводится на новую строку), о которой вам, вероятно, не нужно беспокоиться;он просто сообщает Perl, что такое «разделитель входных записей», что, как я предполагаю, означает, что он определяет, как далеко <FILEHANDLE> читает.Вы можете в значительной степени забыть об этом сейчас, это похоже на сложную тему.Просто притворись, что chomp отрывается от новой строки.Честно говоря, я никогда раньше не слышал о $/.

Что касается вашего другого вопроса, то обычно чище всегда сжимать переменные и добавлять новые строки по мере необходимости позже, потому что вы не всегда знаете, еслипеременная имеет перевод строки или нет;всегда смешивая переменные, вы всегда получаете одинаковое поведение.Есть сценарии, где это не нужно, но если вы не уверены, что это не может повредить chomp.

Надеюсь, это поможет!

3 голосов
/ 03 сентября 2011

ОК, с 1), perl не добавляет \n на входе.Это вы нажали Enter , когда закончили вводить номер.Если вы не укажете $/, будет установлено значение по умолчанию \n (как минимум, под UNIX).

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

Наконец, ошибка, которую вы получаете, может быть из-за того, что perl не понимает вашу переменную в двойных кавычках последнего print, потому что у него есть _ символ.Попробуйте написать строку следующим образом:

print "$input can be reached at ${name_number{$input}}\n";

(обратите внимание на {} вокруг последней переменной).

2 голосов
/ 03 сентября 2011

<STDIN> - сокращенное обозначение для readline( *STDIN );.Функция readline () читает дескриптор файла до тех пор, пока он не встретит содержимое $ / (aka $ INPUT_RECORD_SEPARATOR) и вернет все прочитанное, включая содержимое $ /.chomp() удаляет последнее содержимое вхождения $ /, если оно есть.

Содержимое часто называют символом новой строки, но оно может состоять из нескольких символов.В Linux он содержит символ LF, а в Windows - CR-LF.

См .:

perldoc -f readline
perldoc -f chomp
perldoc perlvar and search for /\$INPUT_RECORD_SEPARATOR/
0 голосов
/ 03 сентября 2011

Хотя это может быть очевидно, все же стоит упомянуть , почему здесь необходим chomp.

Созданный хэш содержит 4 ключа поиска: "Me", "Home", "Emergency" и "Lookup"

Если для <STDIN> указано $input, оно будет содержать "Me\n", "Me\r\n" или какой-либо другой вариант конца строки в зависимости откакая операционная система используется.

Ошибка неинициализированного значения возникает из-за того, что ключ "Me\n" не существует в хэше.И именно поэтому необходим chomp:

my $input = <STDIN>; # "Me\n" --> Key DNE, $name_number{$input} not defined
chomp $input;        # "Me"   --> Key exists, $name_number{$input} defined
0 голосов
/ 03 сентября 2011

Я думаю, что лучшей практикой здесь будет написать:

chomp(my $input = <STDIN>);

Вот краткий пример того, как работает функция chomp (здесь объясняется значение $/), удаляющая только одну завершающую новую строку (если есть):

chomp (my $input = "Me\n"); # OK
chomp ($input = "Me"); # OK (nothing done)
chomp ($input = "Me\n\n"); # $input now is "Me\n";
chomp ($input); # finally "Me"

print "$input can be reached at $name_number{$input}\n"; 

Кстати: забавно то, что я тоже изучаю Perl и достиг хешей пять минут назад.

...