Глава 1: Введение.
1.5. Прогулка по стране Perl
1.5.9. Перенос списка секретных слов в отдельный файл
Допустим, вы хотели бы использовать список секретных слов в трех программах. Если вы сохраните этот список так, как мы уже это делали, нам придется корректировать все три программы (если, например, Бетти решит, что ее секретным словом должно быть не alpaca, a swine). Это может стать настоящим кошмаром, особенно если Бетти отличается непостоянством.
Поэтому давайте поместим список слов в файл, а затем, чтобы ввести список в программу, просто прочитаем файл. Для этого нужно создать канал ввода-вывода, который называется дескриптором файла. Ваша Perl-программа автоматически получает три дескриптора файлов, stdin, stdout и stderr, которые соответствуют трем стандартным каналам ввода-вывода в большинстве сред программирования. Мы уже используем дескриптор stdin для чтения данных, поступающих от пользователя, запускающего нашу программу. Теперь нужно просто создать для выбранного нами файла другой дескриптор.
Это делается с помощью следующего кода:
sub init_words {
open (WORDSLIST, "wordslist");
while ($name = <WORDSLIST” {
chomp ($name);
$word = <WORDSLIST>;
chomp ($word);
$words {$name} = $word;
close (WORDSLIST) ;
Мы помещаем его в подпрограмму, чтобы не загромождать основную программу. Это означает также, что позже мы сможем изменить место хранения списка слов и даже его формат.
Произвольно выбранный формат списка слов — один элемент в строке с чередованием имен и секретных слов. Для нашей базы данных мы имели бы такой список:
fred camel barney llama betty alpaca wilma alpaca
Функция open инициализирует дескриптор файла wordslist, связывая его с файлом wordslist, находящимся в текущем каталоге. Отметим, что перед этим дескриптором не ставится никакого забавного символа, вроде тех трех, что предваряют наши переменные. Кроме того, дескрипторы файлов обычно записываются прописными буквами (хотя это и не обязательно); причины этого мы рассмотрим позднее.
При выполнении цикла while читаются строки из файла wordslist (через дескриптор файла wordslist) по одной при каждом проходе цикла. Каждая строка заносится в переменную $name. По достижении конца файла операция <wordslist> возвращает пустую строку*, которая для цикла while означает "ложь", и завершает цикл.
Если бы вы выполняли программу с ключом -w, вам пришлось бы проверять, определено ли полученное возвращаемое значение. Пустая строка, которую возвращает операция <wordslist>, не совсем пуста: это опять значение undef. В тех случаях, когда это важно, проверка выражения на значение undef производится функцией defined. При чтении строк из файла эта проверка выполнялась бы следующим образом:
while ( defined ($name = <WORDSLIST) ) {
* На самом деле это опять undef, но для понимания данного материала сказанного достаточно.
Но если бы вы были еще более осторожны, вы, вероятно, проверили бы также и то, возвращает ли функция open значение "истина". Это, кстати, в любом случае неплохая идея. Для выхода из программы с сообщением об ошибке в случае, если что-то работает не так, часто используется встроенная функция die. Мы рассмотрим пример этой функции в следующей версии нашей программы.
С другой стороны, при нормальном развитии событий мы считываем строку (включая символ новой строки) в переменную $name. Сначала с помощью функции chomp убирается символ новой строки, затем нужно прочитать следующую строку, чтобы получить секретное слово и сохранить sro в переменной $word. Символ новой строки при этом тоже убирается.
Последняя строка цикла while помещает $word в $words с ключом $name, чтобы переменную $word могла использовать остальная часть программы.
По завершении чтения файла его дескриптор можно использовать повторно, предварительно закрыв файл с помощью функции close. (Дескрипторы файлов автоматически закрываются в любом случае при выходе из программы, но мы стараемся быть аккуратными. Однако если бы мы были по-настоящему аккуратными, мы бы даже проверили бы, возвращает ли close значение "истина" в случае, если раздел диска, в котором был файл, решил "отдохнуть", если сетевая файловая система стала недосягаемой или произошла еще какая-нибудь катастрофа. Такое ведь иногда случается. Законы Мерфи никто не отменял.)
Сделанное выше определение подпрограммы может идти после другого аналогичного определения или перед ним. Вместо того чтобы помещать определение $words в начало программы, мы можем просто вызывать эту подпрограмму в начале выполнения основной программы. Один из вариантов компоновки общей программы может выглядеть так:
#!/usr/bin/perl
init_words() ;
print "What is your name? ";
$name = <STDIN>;
chomp ($name);
if ($name =~ /^randal\b/i) { # обратно на другой путь :-)
print "Hello, Randal! How good of you to be here!\n";
} else {
print "Hello, $name! \n"; # обычное приветствие
print "What is the secret word? ";
$guess = <STDIN>;
chomp ($guess);
While (! good_word($name, $guess)) {
print "Wrong, try again. What is the secret word? ";
$guess = <STDIN>;
chomp ($guess);
} # далее — подпрограммы
sub init_words {
open (WORDSLIST, "wordslist") || die "can't open wordlist: $!";
while {
defined ($name = <WORDSLIST”) ( chomp ($name) ;
$word = <WORDSLIST>;
chomp ($word);
$words($name) = $word;
}
close (WORDSLIST) II die "couldn't close wordlist"
}
sub good_word {
my($somename,$someguess) = @_; # перечислить параметры
$somename =~ s/\W.*//; # удалить все символы, стоящие после первого слова
$somename =~ tr/A-Z/a-z/; # перевести все символы в нижний регистр
if ($somename eq "randal") { # не нужно угадывать
return 1; # возвращаемое значение - true
} elsif (($words($somename) II "groucho") eq $someguess) {
return 1; # возвращаемое значение - true
} else {
return 0; # возвращаемое значение — false
Теперь написанный нами код начинает выглядеть как настоящая "взрослая" программа. Обратите внимание: первая выполняемая строка — вызов подпрограммы init_word(). Возвращаемое значение в последующих вычислениях не используется, и это хорошо, потому что мы не возвратили ничего заслуживающего внимания. В данном случае это гарантированно значение "истина" (в частности, значение 1), потому что если бы close не выполнилась, то die вывела бы сообщение в stderr и вышла из программы. Функция die подробно описывается в главе 10, но поскольку очень важно проверять возвращаемые значения всего, что может завершиться неудачно, мы возьмем за правило использовать эту функцию с самого начала. Переменная $! (тоже рассматривается в главе 10) содержит системное сообщение об ошибке, поясняющее, почему данный системный вызов завершился неудачно.
Функция open используется также для открытия файлов при выводе в них информации и открытия программ как файлов (здесь она лишь упомянута). Полное описание этой функции будет дано гораздо позже, в главе 10.
Назад | Вперед
Содержание (общее) | Содержание раздела | Содержание подраздела
Если Вы не нашли что искали, то рекомендую воспользоваться поиском по сайту:
|