perlform
СОДЕРЖАНИЕ
ИМЯ
perlform - Perl-форматы
ОПИСАНИЕ
Perl имеет механизм, помогающий генерировать простые отчеты и диаграммы. Для этого Perl позволяет вам кодировать страницу вывода вблизи того, как она будет выглядеть при печати. Он может отслеживать количество строк на странице, номер страницы, когда печатать заголовки страниц и т. д. Ключевые слова позаимствованы из FORTRAN: format() для объявления и write() для выполнения; см. их записи в perlfunc. К счастью, макет намного более удобочитаем, больше похож на оператор PRINT USING BASIC. Представьте это как nroff(1) для бедных.
Форматы, как пакеты и подпрограммы, объявляются, а не выполняются, поэтому они могут появляться в любой точке вашей программы. (Обычно лучше держать их все вместе.) У них есть свой собственный пространство имен, отличное от всех других «типов» в Perl. Это означает, что если у вас есть функция с именем «Foo», это не то же самое, что иметь формат с именем «Foo». Однако имя по умолчанию для формата, связанного с заданным файловым дескриптором, совпадает с именем файлового дескриптора. Таким образом, формат по умолчанию для STDOUT называется «STDOUT», а формат по умолчанию для файлового дескриптора TEMP называется «TEMP». Они выглядят одинаково. Они не такие.
Форматы записей вывода объявляются следующим образом:
format NAME =
FORMLIST
. Если имя опущено, определяется формат «STDOUT». Одиночная точка в столбце 1 используется для завершения формата. FORMLIST состоит из последовательности строк, каждая из которых может быть одного из трех типов:
-
Комментарий, указанный путем ввода символа '#' в первый столбец.
-
Строка «рисунка», задающая формат одной строки вывода.
-
Строка аргумента, предоставляющая значения для подстановки в предыдущую строку изображения.
Строки изображения содержат определения полей вывода, перемежающиеся с текстом. Эти строки не проходят никакой интерполяции переменных. Определения полей состоят из набора символов для начала и расширения поля до нужной ширины. Это полный набор символов для определений полей:
@ start of regular field
^ start of special field
< pad character for left justification
| pad character for centering
> pad character for right justification
# pad character for a right-justified numeric field
0 instead of first #: pad number with leading zeroes
. decimal point within a numeric field
... terminate a text field, show "..." as truncation evidence
@* variable width field for a multi-line value
^* variable width field for next line of a multi-line value
~ suppress line with all fields empty
~~ repeat line until all fields are exhausted Каждое поле в строке изображения начинается с символа «@» (собаки) или «^» (крышки), указывающих, что это, соответственно, «обычное» или «специальное» поле. Выбор символов заполнения определяет, является ли поле текстовым или числовым. Операторы тильды не являются частью поля. Давайте рассмотрим различные возможности подробно.
Поля текста
Длина поля задаётся дополнением поля множеством символов «<», «>» или «|» для указания поля без чисел с выравниванием слева, справа или по центру, соответственно. Для обычного поля берется значение (до первой новой строки) и печатается в соответствии с выбранным выравниванием, обрезая избыточные символы. Если вы завершаете текстовое поле «...», три точки будут показаны, если значение обрезано. Специальное текстовое поле может использоваться для выполнения грубого заполнения многострочных блоков текста; см. «Использование режима заполнения» для получения дополнительной информации.
Example:
format STDOUT =
@<<<<<< @|||||| @>>>>>>
"left", "middle", "right"
.
Output:
left middle right Поля чисел
Использование «#» в качестве символа заполнения определяет числовое поле с выравниванием по правому краю. Необязательная точка определяет позицию десятичной точки. С «0» (ноль) вместо первого «#» отформатированное число будет дополнено ведущими нулями при необходимости. Специальное числовое поле останется пустым, если значение не определено. Если полученное значение превысит заданную ширину поля, поле заполняется знаком «#» как свидетельство переполнения.
Example:
format STDOUT =
@### @.### @##.### @### @### ^####
42, 3.1415, undef, 0, 10000, undef
.
Output:
42 3.142 0.000 0 #### Поле @* для многострочного текста переменной ширины
Поле «@*» может использоваться для печати многострочных значений без обрезки; оно должно (но не обязательно) появляться на отдельной строке. Конечный символ новой строки удаляется, но все остальные символы отображаются дословно.
Поле ^* для текстового поля переменной ширины, по одной строке за раз
Подобно «@*», это поле переменной ширины. Предоставленное значение должно быть скалярной переменной. Perl помещает первую строку (до первой «\n») текста в поле, а затем обрезает начало строки, так что при следующем обращении к переменной, можно будет напечатать больше текста. Переменная не будет восстановлена.
Example:
$text = "line 1\nline 2\nline 3";
format STDOUT =
Text: ^*
$text
~~ ^*
$text
.
Output:
Text: line 1
line 2
line 3 Указание значений
Значения указываются в следующей строке формата в том же порядке, что и поля изображения. Выражения, предоставляющие значения, должны быть разделены запятыми. Все они вычисляются в контексте списка перед обработкой строки, поэтому одно выражение списка может произвести несколько элементов списка. Выражения могут быть распределены на несколько строк, если заключены в фигурные скобки. В этом случае открывающая фигурная скобка должна быть первым токеном на первой строке. Если выражение вычисляется в число с десятичной частью, и если соответствующее изображение указывает, что десятичная часть должна отображаться в выводе (то есть любое изображение, кроме нескольких символов «#» без вложенной точки «.»), символ, используемый для десятичной точки, определяется текущим локалем LC_NUMERIC, если use locale активен. Это означает, что, например, если среда выполнения задает немецкий локали, вместо стандартной точки «.» будет использоваться запятая «,» . См. perllocale и «ПРЕДУПРЕЖДЕНИЯ» для получения дополнительной информации.
Использование режима заполнения
Для текстовых полей символ крышки включает своеобразный режим заполнения. Вместо произвольного выражения значение должно быть скалярной переменной, содержащей строку текста. Perl помещает следующий фрагмент текста в поле, а затем обрезает начало строки, так что при следующем обращении к переменной, будет напечатана больше текста. (Да, это означает, что сама переменная изменяется во время выполнения вызова write(), и не восстанавливается.) Следующий фрагмент текста определяется грубым алгоритмом разбиения на строки. Вы можете использовать символ возврата каретки (\r) для принудительного перевода строки. Вы можете изменить символы, разрешенные для разбиения, изменив переменную $: (это $FORMAT_LINE_BREAK_CHARACTERS, если вы используете модуль English) на список желаемых символов.
Обычно вы использовали бы последовательность полей в вертикальном стеке, связанных с одной и той же скалярной переменной, чтобы напечатать блок текста. Возможно, вы захотите завершить последнее поле текстом «...», который появится в выводе, если текст был слишком длинным, чтобы отобразиться полностью.
Скрытие строк, где все поля пустые
Использование полей с крышкой может создавать строки, где все поля пустые. Вы можете скрыть такие строки, поместив символ «~» (тильду) в любом месте строки. Тильда будет преобразована в пробел при выводе.
Повтор строк формата
Если вы поместите два смежных символа тильды «~~» в любую строку, строка будет повторяться, пока все поля в строке не будут исчерпаны, т.е. не будут определены. Для специальных (с крышкой) текстовых полей это произойдёт рано или поздно, но если вы используете текстовое поле типа «@», выражение, которое вы предоставите, лучше не должно давать одно и то же значение бесконечно! (shift(@f) — простой пример, который сработает). Не используйте обычное (собаки) числовое поле в таких строках, потому что оно никогда не станет пустым.
Обработка начала формы
Обработка начала формы по умолчанию обрабатывается форматом с тем же именем, что и текущий файловый дескриптор, со строкой «_TOP», добавленной к нему. Она запускается в начале каждой страницы. См. "write" в perlfunc.
Примеры:
# a report on the /etc/passwd file
format STDOUT_TOP =
Passwd File
Name Login Office Uid Gid Home
------------------------------------------------------------------
.
format STDOUT =
@<<<<<<<<<<<<<<<<<< @||||||| @<<<<<<@>>>> @>>>> @<<<<<<<<<<<<<<<<<
$name, $login, $office,$uid,$gid, $home
.
# a report from a bug report form
format STDOUT_TOP =
Bug Reports
@<<<<<<<<<<<<<<<<<<<<<<< @||| @>>>>>>>>>>>>>>>>>>>>>>>
$system, $%, $date
------------------------------------------------------------------
.
format STDOUT =
Subject: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$subject
Index: @<<<<<<<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$index, $description
Priority: @<<<<<<<<<< Date: @<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$priority, $date, $description
From: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$from, $description
Assigned to: @<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$programmer, $description
~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$description
~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$description
~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$description
~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$description
~ ^<<<<<<<<<<<<<<<<<<<<<<<...
$description
. Можно смешивать print() с write() в одном и том же канале вывода, но вам придется обрабатывать $- ($FORMAT_LINES_LEFT) самостоятельно.
Переменные формата
Текущее имя формата хранится в переменной $~ ($FORMAT_NAME), а текущее имя формата начала формы хранится в $^ ($FORMAT_TOP_NAME). Текущий номер страницы вывода хранится в $% ($FORMAT_PAGE_NUMBER), а количество строк на странице — в $= ($FORMAT_LINES_PER_PAGE). Автоматически ли буферизировать вывод в этом дескрипторе файла хранится в $| ($OUTPUT_AUTOFLUSH). Строка вывода перед каждым началом страницы (кроме первой) хранится в $^L ($FORMAT_FORMFEED). Эти переменные устанавливаются для каждого файлового дескриптора, поэтому вам нужно выбрать другой, чтобы повлиять на них:
select((select(OUTF),
$~ = "My_Other_Format",
$^ = "My_Top_Format"
)[0]); Довольно плохо, да? Однако это распространённый приём, так что не удивляйтесь, увидев его. По крайней мере, вы можете использовать временную переменную для хранения предыдущего файлового дескриптора: (это гораздо лучший подход в целом, так как удобочитаемость улучшается, а у вас теперь есть промежуточная стадия в выражении для пошагового отладчика):
$ofh = select(OUTF);
$~ = "My_Other_Format";
$^ = "My_Top_Format";
select($ofh); Если вы используете модуль English, вы можете даже прочитать имена переменных:
use English;
$ofh = select(OUTF);
$FORMAT_NAME = "My_Other_Format";
$FORMAT_TOP_NAME = "My_Top_Format";
select($ofh); Но у вас всё ещё есть эти странные select(). Поэтому просто используйте модуль FileHandle. Теперь вы можете получить доступ к этим специальным переменным, используя имена методов в нижнем регистре:
use FileHandle;
format_name OUTF "My_Other_Format";
format_top_name OUTF "My_Top_Format"; Гораздо лучше!
ПРИМЕЧАНИЯ
Поскольку строка значений может содержать произвольные выражения (для полей типа «@», а не «^»), вы можете передать более сложную обработку другим функциям, таким как sprintf() или вашей собственной. Например:
format Ident =
@<<<<<<<<<<<<<<<
&commify($n)
. Чтобы получить реальную собаку или крышку в поле, сделайте так:
format Ident =
I have an @ here.
"@"
. Чтобы выровнять по центру целую строку текста, сделайте что-то вроде этого:
format Ident =
@|||||||||||||||||||||||||||||||||||||||||||||||
"Some text line"
. Нет встроенного способа сказать «выровнять это по правому краю страницы, независимо от ширины». Вам нужно указать, куда его поместить. В отчаянии можно сгенерировать собственный формат на лету, основываясь на текущем количестве столбцов, а затем использовать eval():
$format = "format STDOUT = \n"
. '^' . '<' x $cols . "\n"
. '$entry' . "\n"
. "\t^" . "<" x ($cols-8) . "~~\n"
. '$entry' . "\n"
. ".\n";
print $format if $Debugging;
eval $format;
die $@ if $@; Что сгенерирует формат примерно такого вида:
format STDOUT =
^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$entry
^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~
$entry
. Вот небольшая программа, которая чем-то похожа на fmt(1):
format =
^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~~
$_
.
$/ = '';
while (<>) {
s/\s*\n\s*/ /g;
write;
} Подвалы
Хотя $FORMAT_TOP_NAME содержит имя текущего формата заголовка, нет соответствующего механизма для автоматической обработки подвала. Невозможность узнать размер формата до его оценки — одна из основных проблем. Это в списке задач.
Вот одна стратегия: если у вас подвал фиксированного размера, вы можете проверить $FORMAT_LINES_LEFT перед каждым write() и самостоятельно напечатать подвал, если это необходимо.
Вот другая стратегия: откройте канал к себе, используя open(MYSELF, "|-") (см. "open" в perlfunc) и всегда записывайте в MYSELF вместо STDOUT. Пусть дочерний процесс обрабатывает свой STDIN, чтобы переупорядочить заголовки и подвалы по вашему желанию. Не очень удобно, но возможно.
Доступ к внутренностям форматирования
Для низкоуровневого доступа к механизму форматирования вы можете использовать formline() и получить доступ к $^A (переменной $ACCUMULATOR) напрямую.
Например:
$str = formline <<'END', 1,2,3;
@<<< @||| @>>>
END
print "Wow, I just stored '$^A' in the accumulator!\n"; Или для создания подпрограммы swrite(), которая для write() то же, что sprintf() для printf(), сделайте так:
use Carp;
sub swrite {
croak "usage: swrite PICTURE ARGS" unless @_;
my $format = shift;
$^A = "";
formline($format,@_);
return $^A;
}
$string = swrite(<<'END', 1, 2, 3);
Check me out
@<<< @||| @>>>
END
print $string; ПРЕДУПРЕЖДЕНИЯ
Одиночная точка, которая завершает формат, также может преждевременно завершить сообщение электронной почты, проходящее через неправильно настроенный почтовый сервер (и, исходя из опыта, такая неправильная настройка — правило, а не исключение). Поэтому при отправке кода формата по электронной почте вы должны отступать, чтобы точка, завершающая формат, не находилась на левом отступе; это предотвратит обрезание SMTP.
Лексические переменные (объявленные с помощью "my") не видны внутри формата, если формат не объявлен в области видимости лексической переменной.
Если среда программы определяет локаль LC_NUMERIC, и use locale активна, когда объявлен формат, локаль используется для определения символа десятичной точки в отформатированном выводе. Отформатированный вывод не может контролироваться use locale в момент вызова write(). См. perllocale для дополнительного обсуждения обработки локалей.
В строках, которые должны отображаться в текстовом поле фиксированной длины, каждый управляющий символ заменяется пробелом. (Но помните о специальном значении \r при использовании режима заполнения.) Это делается для предотвращения смещения при «исчезновении» управляющих символов на некоторых устройствах вывода.
© 1993–2020 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.28.3/perlform