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), и всегда выполняйте write() в 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–2021 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.34.0/perlform