Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
kernigan_paik.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
2.91 Mб
Скачать

3.7. Awk и Perl

Чтобы завершить наши упражнения, мы написали программу еще и на двух популярных языках скриптов — Awk и Perl. В них есть воз­можности, необходимые для нашего приложения, — ассоциативные мас­сивы и методы обработки строк.

Ассоциативный массив (associative array) — это подходящий контей­нер для хэш-таблицы; он выглядит как простой массив, но его индексами являются произвольные строки, или числа, или наборы таких элемен­тов, разделенных запятыми. Это разновидность отображения данных одного типа в данные другого типа. В Awk все массивы являются ассо­циативными; в Perl есть как массивы, индексируемые стандартным об­разом, целочисленными индексами, так и ассоциативные массивы, кото­рые называются "хэшами" (hashes), — из их названия сразу становится ясен способ их внутренней реализации.

Предлагаемые версии на Awk и Perl рассчитаны только на работу с префиксами длиной в два слова.

# markov.awk: алгоритм цепей Маркова для префиксов из 2 слов

BEGIN { MAXGEN = 10000; NONWORD = "\пм; w1 = w2 = NONWORD }

{ for (i = 1; i <= NF; i++) { # читать все слова

Statetab[w1,w2,++nsuffix[w1,w2]] = $i

w1 = w2

w2 = $i

}

}

END {

Statetab[w1,w2,++nsuffix[w1,w2]] = NONWORD

# добавить метку конца ввода

w1 = w2 = NONWORD

for (1=0; i < MAXGEN; i++) { # генерируем

r = int(rand()*nsuffix[w1,w2]) + 1 # nsuffix >= 1

p = statetab[w1,w2, r]

if (p == NONWORD)

exit

print p

wl = w2 # идти дальше по цепочке

w2 =.p

}

}

Awk — язык, функционирующий по принципу "образец-действие": входной поток читается по строке за раз, каждая строка сравнивается с образцом, для каждого совпадения выполняется соответствующее дей­ствие. Существуют два специальных образца — BEGIN и END, которые вызываются, соответственно, перед первой строкой ввода и после по­следней.

Действие — это блок выражений, заключенный в фигурные скобки. В Awk-версии в блокеBEGIN инициализируется префикс и пара других переменных.

Следующий блок не имеет образца, поэтому он по умолчанию вызы­вается для каждой новой строки ввода. Awk автоматически разделяет каждую вводимую строку на поля (ограниченные пробелами слова), имеющие имена от $1 до $NF; переменная NF — это количество полей. Вы­ражение

statetab[w1,w2,++nsuffix[w1,w2]] = $i

создает отображение префиксов в суффиксы. Массив nsuffix считает суффиксы, а элемент

nsuffix[w1, w2] считает количество суффиксов, ас­социированных с префиксом. Сами суффиксы хранятся в элементах мас­сива statetab[w1, w2,1], statetab[w1, w2, 2] и т. д.

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

Версия Perl выглядит похожим образом, но в ней для хранения суф­фиксов используется безымянный массив, а не третий индекс; для об­новления же префикса используется множественное присваивание. В Perl для обозначения типов переменных применяются специальные символы: $ обозначает скаляр, @ — индексированный массив, квадрат­ные скобки [ ] используются для индексации массивов, а фигурные скобки { } — для индексации хэшей.

# markov.pl: алгоритм цепей Маркова для префиксов из 2 слов

$MAXGEN = 10000;

$NONWORD = “\n”;

$w1 = $w2 = $NONWORD; # начальное состояние

while (<>) { # читать каждую строку ввода

forech (split) {

push(@{$statetab{$w1}{$w2}}, $_);

($w1, $w2) = ($w2, $_); # множественное присваивание

}

}

push(@{$statetab{$w1}{$w2}}, $NONWORD);

# добавить метку конца ввода

$w1 = $w2 = $NONWORD;

for ($i =0; $i < $MAXGEN; $i++) {

$suf = $statetab{$w1}{$w2}; # ссылка на массив

$r = int(rand @$suf); # @$suf - количество элементов

exit if (($t = $suf->[$r]) eq $NONWORD);

print "$t\n";

($w1, $w2) = ($w2, $t); # обновить префикс

}

Как и в предыдущей программе, отображение хранится при помощи пе­ременной statetab. Центральным моментом программы является выра­жение

push(@{$statetab{$w1}{$w2}}, $_);

которое дописывает новый суффикс в конец (безымянного) массива, хранящегося в statetab{$w1}{$w2}. На этапе генерации $statetab{$w1}{$w2} является ссылкой на массив суффиксов, a $suf->[$r] указывает на суф­фикс, хранящийся под номером r.

Программы и на Awk, и на Perl гораздо короче, чем любая из трех пре­дыдущих версий, но их тяжелее адаптировать для обработки префиксов, состоящих из произвольного количества слов. Ядро программ на С и C++ (функции add и generate) имеет сравнимую длину, но выглядит более понятно. Тем не менее языки скриптов нередко являются хорошим выбо­ром для экспериментального программирования, для создания прототи пов и даже для производственного использования в случаях, когда время счета не играет большой роли.

Упражнение 3-7

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]