Spec-Zone.ru › Perl 5.36

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 состоит из последовательности строк, каждая из которых может быть одного из трех типов:

  1. Комментарий, указанный путем размещения символа «#» в первом столбце.

  2. Строка «рисунка», задающая формат одной строки вывода.

  3. Строка аргумента, предоставляющая значения для подстановки в предыдущую строку рисунка.

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

@    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
.

Возможна смешанная печать() с write() в одном и том же канале вывода, но вы должны обработать $- ($FORMAT_LINES_LEFT) самостоятельно.

Переменные формата

Текущее имя формата хранится в переменной $~ ($FORMAT_NAME), а имя текущего формата начала формы — в $^ ($FORMAT_TOP_NAME). Текущий номер страницы вывода хранится в $% ($FORMAT_PAGE_NUMBER), а количество строк на странице — в $= ($FORMAT_LINES_PER_PAGE). Автоматический сброс вывода для этого дескриптора хранится в $| ($OUTPUT_AUTOFLUSH). Строка вывода перед началом каждой страницы (кроме первой) хранится в $^L ($FORMAT_FORMFEED). Эти переменные задаются для каждого файлового дескриптора, поэтому вам нужно будет использовать select() для другого дескриптора, чтобы повлиять на них:

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) и всегда вызывайте 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.36.0/perlform

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API