| Содержание | Предисловие | В

Глава 11

    В этой главе:


Форматы

Что такое формат

Помимо всего прочего, Perl — это, как мы уже говорили, "практический язык извлечений и отчетов". Теперь самое время узнать

В Perl существует понятие шаблона для написания отчета, который называется форматом. В формате определяется постоянная часть (заголовки столбцов, метки, неизменяемый

Использование формата предполагает выполнение трех операций:

1. Определение формата.

2. Загрузка данных, подлежащих печати, в переменные части формата (поля).

3. Вызов формата.

Чаще всего первый этап выполняется один раз (в тексте программы, чтобы формат определялся во время компиляции)*, а два остальных этапамногократно.

* Форматы можно создавать и во время выполнения, пользуясь функцией eval (см. книгу P

Определение формата

Формат задается с помощью специальной конструкции, которая называется определением формата. Определение формата, как и подпрограмма, может стоять в любом месте программы. Выглядит оно т

format имя_формата =

строка_полей

значение_один, значение_два, значение_три

строка_полей

значение_один, значение_два

строка_полей

значение_один, значение_два, значение_три

Первая строка содержит зарезервированное слово format, за которым следует имя формата и знак равенства (=).За первой строкой идет сам шаблон, который может включать несколько текстовых строк или быть "пустым", т.е. не содержать ни одной строки. Конец шаблона обозначается точкой, которая ставится в отдельной строке*. В шаблонах разные

Определение шаблона содержит ряд строк полей. Каждая строка полей может содержать неизменяемый текст текст, который будет выведен буквально при вызове формата. Вот

Hello, my name is Fred Flintstone.

Строки полей могут содержать поледержатели (fieldholder, или переменные полей) для изменяемого текста. Если строка содержит

Hello, my name is @“““““ $name

* В текстовых файлах последняя строка должна заканчиваться символом новой строки.

Поледержатель здесь @“““““. Этот поледержатель задает текстовое поле, которое состоит из 11Если в строке полей имеется несколько поледержателей, то в следующей строке должны быть указаны несколько значений. Эти значения отделяются друг от друга запятыми:

Hello, my name is @“““““ and I'm @“ years old. $name, $age

Собрав все вместе, мы создадим простой формат для вывода адреса:

format ADDRESSLABEL =

$name

$ address | @<“““““““, @< @““ |

$city, $state, $zip

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

Пробельные символы в строке значений игнорируются. Некоторые предпочитают вставлять в строку значений дополнительные пробельные символы, чтобы выравнять переменные по поледержателям в предыдущей строке (например, в только что рассмотрен

Текст, стоящий в строке значений после первого символа новой строки, отбрасывается (за исключением особого случая с многострочными поледер-жателями, который будет рассмотрен ниже).

Определение формата похоже на определение подпрограммы. Оно не содержит немедленно выполняемого кода и может поэтому располагаться в любом месте файла программы. Мы предпочитаем ставить определение формата ближе к концу файла, перед опр

Вызов формата

Вызов формата производится с помощью функции write. Эта функция получает имя дескриптора файла и генерирует для этого деск

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

format ADDRESSLABEL =

$name

$address

$city, $state, $zip

open(ADDRESSLABEL,">labels-to-print") || die "can't create";

open (ADDRESSES,"addresses") || die "cannot open addresses";

while (<ADDRESSES>) f

chomp; # удалить символ новой строки

($name,$address,$city,$state,$zip) = split (/:/);

# загрузить глобальные переменные

write (ADDRESSLABEL); # send the output }

Здесь мы видим уже знакомое определение формата, но теперь у нас есть и выполняемый код. Сначала мы открываем дескриптор для выходного файла, который называется labels-to-pr

Stonehenge:4470 SW Hall Suite 107 :Beaverton:OR:97005 Fred Flintstone:3737 Hard Rock Lane:Bedrock:OZ:999bc

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

Цикл while в программе считывает строку из файла адресов, избавляется от символа новой строки, а затем разбивает то, что осталось, на пять переменных. Обратите внимание: име

После загрузки значений всех необходимых для работы с форматом переменных функция write вызывает формат. Отметим, что параметром функции writeКаждое поле в формате заменяется соответствующим значением из следующей строки формата. После обработки двух приведенных в примере записей файл labels-to-print будет содержа

Stonehenge

4470 SW Hall Suite 107

Beaverton , OR 97005

Fred Flintstone 3737 Hard Rock Lane Bedrock , OZ 999bc

Еще о поледержателяж

Из примеров вы уже поняли, что поледержатель @““ обозначает выровненное по левому краю поле, которое содержит пять символов, а @“““““

Текстовые поля

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

Если после знака @ стоят левые угловые скобки (““), поле выровнено по левому краю, т.е. в случае, если значение окажется короче, чем отведенное для него поле, оно будет допо

Если после знака @ стоят правые угловые скобки (””), поле выровнено по правому краю, т.е. в случае, если значение окажется короче, чем отведенное для него поле, оно будет за

Наконец, если символы, стоящие после знака @, повторяющаяся несколько раз вертикальная черта (||||), то поле центрировано. Это означает, что если значение слишком короткое

Числовые поля

Следующий тип поледержателя числовое поле с фиксированной десятичной запятой, полезное для больших финансовых отчетов. Э

format MONEY =

Assets: @#W#.*” Liabilities: @#*”##.*# Net: @t”##*.*#

$assets, $liabilities, $assets-$liabilities

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

Ничего оригинального в Perl больше нет: вам не удастся установить формат с плавающей запятой для вывода значений денежных сумм, нельзя также заключить отрицательные значения

format MONEY =

Assets: @“““<“ Liabilities: @““““ Net: @““<““

&cool($assets,10), scool($liab,9), Scool($assets-$liab,10)

sub pretty (

my($n,$width) = @_;

$width - 2; # учтем отрицательные числа

$n ° sprintf("%.2f",$n); # sprintf описывается в одной из следующих глав if ($n < 0) (

return sprintf ("[t$width.2f]", -$n); # отрицательные числа

# заключаются в квадратные скобки ) else {

return sprintf (" %$width.2f ", $n); # положительные числа выделяются

^ пробелами } }

## body of program:

$assets = 32125.12;

$liab = 45212.15;

write (MONEY) ;

Многостроковые поля

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

четыре строки значения становятся четырьмя строками выходной информации. Например, приведенный ниже фрагмент программы

format STDOUT = Text Before. @*

$long_string Text After.

$long_string = "Fred\nBarney\nBetty\nWilma\n";

write;

позволяет получить такие выходные данные:

Text Before.

Fred

Barney

Betty

Wilma

Text After.

Заполненные поля

Следующий вид поледержателя заполненное поле. Этот поледержатель позволяет создавать целый текстовый абзац, разбиение на

Во-первых, заполненное поле обозначается путем замены маркера @ в текстовом поледержателе на символ А (например, /'<“). Соответствующее значе

Когда Perl заполняет данный поледержатель, он берет значение этой переменной и "захватывает" из него столько слов (подразумевая разумное определение термина "слово")**, скол

* А также отдельным скалярным элементом массива или хеша, например, $а[3] или $h{"fred").

** Разделители слов задаются переменной $:.

Пока что особой разницы между заполненным полем и обычным текстовым полем не видно; мы выводим в поле ровно столько слов, сколько в нем умещается (за исключением того, что мы соблюдаем границу

format PEOPLE =

Name: @<““““““ Comment: "““““““““““^“““^ $name, $comment

$comment $comment $comment

Обратите внимание: переменная $ comment появляется четыре раза. Первая строка (строка с полем имени) выводит имя и первые нескольк

Что будет, если полный текст занимает меньше четырех строк? Получатся одна-две пустые строки. Это, наверно, нормально, если вы печатаете этикетки и вам нужно, чтобы в каждом элементе было одинаковое количество строк. Если же вы печатает

Чтобы решить эту проблему, нужно использовать признак подавления. Строка, содержащая тильду (~), подавляется (не выводится), если при печати она окажется пустой (т.е. будет содержать только пробельные символы). Сама тильда всегда печата

format PEOPLE = Name: @““““““< Comment: ^“““““““““““““x

$name, $comment

$comment $comment $comment

Теперь, если комментарий занимает всего две строки, третья и четвертая строки будут автоматически подавлены.

Что будет, если комментарий занимает больше четырех строк? Мы могли бы сделать около двадцати копий последних двух строк этого формата, надеясь, что двадцати строк хватит. Это, однако, противоречит идее о том, что Pe

format PEOPLE = Name: @<““““““ Comment: ^“““““““““““““^

$name, $comment

$comment

Таким образом, все будет нормально, сколько бы строк ни занимал комментарий одну, две или двадцать.

Отметим, что данный критерий прекращения повторения строки требует, чтобы в некоторый момент данная строка стала пустой. Это значит, что в этой строке не нужно размещать постоянный текст (кроме символов пробела и тильд), иначе она никог

Формат начала страницы

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

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

Переменная $% в Perl определяется как количество вызовов формата начала страницы для конкретного дескриптора ф

format ADDRESSLABEL_TOP = My Addresses -- Page @< $%

Длина страницы по умолчанию — 60 строк. Этот параметр можно изменить, присвоив значение специальной переменной, о которой вы вскор

Perl не замечает, если вы выполняете для этого же дескриптора файла функцию print из другого места в программе

Изменение в форматах установок по умолчанию

Мы часто говорим об использовании в тех или иных ситуациях значений "по умолчанию". В Perl имеется способ отмены этих "умо

Изменение дескриптора файла с помощью функции select()

Когда мы говорили о функции print в главе 6, я упомянул, чт

Вначале выбранный в текущий момент дескриптор файла это stdout, благодаря чему упрощается отправка данны

print "hello world\n"; # аналогично print STDOUT "hello worldVn"

select (LOGFILE); # выбрать новый дескриптор файла

print "howdy, world\n"; # аналогично print LOGFILE "howdy, world\n"

print "more for the log\n"; # еще в LOGFILE

select (STDOOT); # вновь выбрать STDOUT

print "back to stdout\n"; # это идет на стандартный вывод

Отметим, что операция select — "липкая"; после выбора нового дескриптора он остается "выбранным в текущий момент" до проведения сл

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

Оказывается, значение, возвращаемое функцией select, — это строка, которая содержит имя ранее выбранного дескриптора. Получив данное значение, можно впоследствии восстановит

$oldhandle = select LOGFILE;

print "this goes to LOGPILEW;

select ($oldhandle); # восстановить предыдущий дескриптор

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

Изменение имени формата

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

Например, чтобы использовать формат addresslabel с дескриптором stdout, следует просто записать:

$~ = "ADDRESSLABEL";

А что, если нужно установить для дескриптора report формат summary?

$oldhanlde =• select REPORT;

$~ ° "SUMMARY";

select ($oldhandle);

Когда в следующий раз мы напишем

write (REPORT) ;

то тем самым передадим текст на дескриптор report, но в формате summary*.

Обратите внимание на то, что вы сохранили предыдущий дескриптор в скалярной переменной, а затем восстановили его. Этот прием признак хорошего ст

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

Изменение имени формата начала страницы

Точно так же, как путем установки переменной $~ мы можем изменять имя формата для конкретного дескриптора файла, так путем установки переменной $

* Объектно-ориентированный модуль FileHandle, входящий в состав стандартного дистрибутива

Изменение длины страницы

Если определен формат начала страницы, длина страницы приобретает особое значение. По умолчанию длина страницы равна 60 ст

Иногда 60 строк не то, что нужно. Этот параметр можно изменить, установив переменную $=.

$old = select LOGFILE; # выбрать LOGFILE и сохранить старый дескриптор $= ° 30;

select $old;

Изменение длины страницы вступает в силу только при следующем вызове формата начала страницы. Если вы установили новую длину перед выводом текста в дескриптор файла в каком-то формате, то все б

Изменение положения на странице

Если вы выводите свой текст в дескриптор файла с помощью функции print, то значение счетчика строк будет неправильным, пот

Например, чтобы сообщить Perl, что вы послали в STDOUT дополнительн

write; # вызвать формат STDOUT для STDOUT

print "An extra line... oops!\n"; # это идет в STDOUT $- --; # декрементировать $-,write; # сработает, учтя дополнительную строку

В начале программы $- устанавливается в нуль для каждого дескриптора файла. Это позволяет гарантировать, что формат начала страниц

Упражнения

Ответы см. в приложении А.

1. Напишите программу, которая открывает файл /etc/passwd по имени и выводит на экран имя пользователя,

2. Добавьте в предыдущую программу формат начала страницы. (Если ваш файл паролей относительно короткий, то, возможно, придется установить длину страницы где-то в 10<

3. Добавьте в начало страницы номер страницы, чтобы при их выводе указывалось page I, page 2 и т.д.




|     Назад     | &n

| Содержание | Предисловие | В



Сайт создан в системе uCoz