Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [ 16 ] 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103

Ведение базы данных о времени правильного ввода секретных слов

Давайте проследим за тем, когда каждый пользователь последний раз правильно вводил свой вариант секретного слова. Очевидно, единственная структура данных, которая годится для этого - хеш. Например, оператор

$last good{$name) = time;

присваивает значение текушего времени, выраженное во внутреннем формате (некоторое большое целое, свыше 800 миллионов, число, которое увеличивается на единицу каждую секунду) элементу хеша %last good, имеющему указанное имя в качестве ключа. В последующем это даст базу данных о времени последнего правильного ввода секретного слова каждым из пользователей, который вызывал эту программу.

При этом, однако, в промежутках между вызовами программы хеш не существует. Каждый раз, когда программа вызывается, формируется новый хеш, т.е. по большому счету мы всякий раз создаем одноэлементный хеш, а по завершении выполнения программы немедленно про него забываем.

Функция dbmopen* отображает хеш в файл (фактически в пару файлов), известный как DBM-файл. Она используется следующим образом:

dbmopen (%last good,"lastdb",0666) И

die "cant dbmopen lastdb: $!",

$last good($narae) = time;

dbmclose (%last good) It die "cant dbrnclose lastdb: $!";

Первый оператор выполняет отображение, используя имена файлов lastdb.dir и lastdb.рад (это общепринятые имена для файлов lastdb, образующих DBM-файл). Если эти файлы необходимо создать (а это бывает при первой попытке их использования), то для них устанавливаются права доступа 0666**. Такой режим доступа означает, что все пользователи могут читать и осуществлять запись в эти файлы. Если вы работаете в UNIX-сис-теме, то описание битов прав доступа к файлу вы найдете на man-странице chmod{2). В других системах chmodQ может работать так же, а может и не работать. Например, в MS-DOS для файлов не устанавливаются права доступа, тогда как в Windows NT - устанавливаются. Если уверенности нет, прочтите описание версии вашей системы.

Второй оператор показывает, что мы используем этот преобразованный хеш как первоначальный. При этом, однако, при создании или корректировке какого-либо элемента хеша автоматически обновляются файлы, образующие DBM-файл. При последующем обращении к хешу значения его элементов поступают непосредственно из его отображения на диске. Благодаря этому

* Можно также использовать низкоуровневую функцию tie с конкретной базой данных; этот вариант подробно описан в главах 5 и 7 книги Programming Perl и на man-страницах perlite(\) и AnyDMBJile (3).

** Фактически права доступа к этим файлам определяются в результате выполнения логической операции И над числом 0666 и текущим значением переменной umask вашего процесса



механизму хеш физически существует и в периоды между вызовами данной программы.

Третий оператор отсоединяет хеш от DBM-файла, делая это практически так же, как операция close закрывает файл.

Хотя все вновь введенные нами операторы позволяют вести базу данных (и даже обеспечивают ее создание), у нас пока нет никакого способа получить имеющуюся в этой базе данных информацию. Для этого придется создать отдельную программку, которая выглядит примерно так:

#!/usr/bin/perl

dbmopen (%last good, "lastdb", 0666)

die "cant dbmopen lastdb: $!"; foreach $name (sort Iceys (%last good) ) ( $when = $ last good{Sname};

$hours = (timeO - $when) / 3600; # вычислить истекшее время в часах write;

format STDOUT =

User @<«<<«<<<<: last correct guess was (?<<< hours ago.

$name, $hours

Здесь мы осуществляем несколько новых операций: выполняем цикл foreach, сортируем список и получаем значения ключей массива.

Сначала функция keys принимает имя хеша в качестве аргумента и возвращает список значений всех ключей этого хеша в произвольном порядке. Для хеша %words, описанного ранее, результат будет примерно таким: fred, barney, betty, wilma, причем имена могут быть перечислены в произвольном порядке. В случае хеша %last good результатом будет список всех пользователей, которые правильно ввели свои секретные слова.

Функция sort сортирует этот список в алфавитном порядке (как если бы вы пропустили текстовый файл через фильтр sort). Это гарантирует, что список, обрабатываемый следующим далее оператором foreach, всегда будет отсортирован по алфавиту.

Уже упомянутый Perl-оператор foreach очень похож на оператор foreach shell С. Он получает список значений и присваивает каждое из них по очереди какой-либо скалярной переменной (в нашем случае - переменной $name), выполняя для каждого значения по одному разу проход цикла (блок). Так, для пяти имен в списке %last good мы делаем пять проходов, при этом каждый раз переменная $name имеет другое значение.

При выполнении цикла foreach происходит загрузка пары переменных, используемых затем в формате stdout, и вызывается этот формат. Обратите внимание: мы вычисляем "возраст" файла, вычитая записанное (в массиве) системное время из текущего времени (которое возвращает функция time), а затем деля результат на 3600 (чтобы преобразовать секунды в часы).



в Perl используются также удобные способы создания и ведения текстовых баз данных (например, файла паролей) и баз данных с фиксированной длиной записей (таких, как база данных "последней регистрации", которую ведет программа login). Эти способы описаны в главе 17.

Окончательные варианты программ

Здесь вашему вниманию предлагаются программы, которые мы писали в этой главе, в окончательном виде. Сначала - программа-приветствие:

#I/usr/bin/perl

&init words ( ) ;

print "what is your name " ;

$name = <STDIN>;

chomp ($name);

if ($name =~ /randalXb/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;

dbmopen {%last good, "lastdb", 0666); $last good($name) = time; dbmclose (%last good); sub init words (

while ($filename = <:*.secret>) ( open (WORDSLIST, $filename) I I

die "cant open $filename: $"; if (-M WORDSLIST < 7) {

while {$name = <WORDSLIST>) ( chomp ($name) ; $word = <WORDSLIST> ; chomp (Sword); $words {$name) = $word ;

) else ( # rename the file so it gets noticed rename ($filename, "$filename.old") I I

die "cant rename $filename.old: $";

close WORDSLIST;

sub good word {

my($somename,Ssomeguess) = @ ; # перечислить параметры

Ssomename =~ s/\W.* ; # удалить все символы, стоящие после первого слова $somename =~ tr/A-Z/a-z/; # перевести все символы в нижний регистр if ($somename eq "randal") { # не нужно угадывать



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [ 16 ] 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103