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"
. Нет встроенного способа сказать «поместить это справа на странице, независимо от ширины». Вы должны указать, куда это нужно.
Наименее опытные программисты могут генерировать свой собственный формат на лету, основываясь на текущем количестве столбцов, а затем оценить его:
$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–2023 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.38.0/perlform