PERLFORM(1) USER COMMANDS PERLFORM(1)
NAME
perlform - Perl のフォーマット文
DESCRIPTION
Perl は、単純なレポートやチャートを作成するお手伝いができま
す。 これを簡単にするために、Perl では、印字された時にどの
ように見えるかに近い形で、コードの中で出力ページをレイアウト
できます。 Perl はまた、1 ページに何行入るか、現在何ページ
めか、いつページヘッダを出力するかといったことのめんどうをみ
てくれます。 使用されるキーワードは FORTRAN から持ってきた
もので、宣言に format 文を用い、実行に write() を使います。
perlfunc manpage で formline と write の項を参照してください。
幸い、レイアウトは BASIC の PRINT USING 文のようなものより読
みやすいものです。 安上がりな nroff(1) と考えてください。
フォーマットは、パッケージやサブルーティンと同じく、実行文で
はなく、宣言文ですから、プログラムのどこにおいてもかまいませ
ん。 (しかしながら、普通は 1 か所にまとめておいた方が良いで
しょう。) フォーマットは Perl の他の「型」とは別に名前空間
がとられます。 このことは、"Foo" という名前の関数を持ってい
るとき、それは、"Foo" という名前のフォーマットを持っているの
とは違うということです。 しかし、あるファイルハンドルに対し
て付随するフォーマットのデフォルトの名前は、そのファイルハン
ドルの名前と同じものです。 つまり、STDOUT に対するデフォル
トのデフォルトのフォーマットは "STDOUT" であり、ファイルハン
ドル TEMP に対するデフォルトのフォーマット名は "TEMP" だとい
うことです。 これらは同じように見えますが、違うものです。
出力レコードのフォーマットは以下のように宣言します:
format NAME =
FORMLIST
.
NAME を指定しないと、"STDOUT" というフォーマットが定義されま
す。 FORMLIST は行の並びからなり、それぞれの行は次の 3 つの
どれかになります:
1. コメント。 行頭に # を置くとその行はコメントとして扱わ
れます。
2. ピクチャ行。 出力する行のフォーマットを 1 行単位で示し
ます。
3. 引数行。 先行するピクチャ行に埋め込む値を示します。
ピクチャ行は、ある種のフィールドが、その行に値を埋め込むのに
使われる他は、まったく見た目の通りに印字されます。 ピクチャ
行の各々のフィールドは、"@" や "^" で始まるようになっていま
す。 ピクチャ行では、いかなる形でも変数の展開は行なわれませ
ん。 "@" フィールド (配列の "@" と混同しないこと) は、通常
のフィードで、"^" フィールドが複数行に渡るテキストのブロック
Perl manpages Last change: Release 5.0 Patchlevel 00 1
PERLFORM(1) USER COMMANDS PERLFORM(1)
を作るために使われます。 フィールドの長さは、"@" や "^" の
あとに "<" や ">" や "|" を必要な数だけ並べることで表わし、
それぞれ、左づめ、右づめ、センタリングを表わします。 もし、
値がフィールドをはみだす場合には、切り捨てられてしまいます。
右づめの別の形式として、数値フィールドを示す、"#" (と "." も
可) を使うこともできます。 この方法で、小数点の位置を揃える
ことができます。 こういったフィールドに与えられる値に改行が
含まれていると、その改行までのテキストが印字されます。 もう
1 つ "@*" というフィールドを使うと、値の切捨てを行なわずに、
複数行にわたって印字するために使用するようにできます。 この
フィールドを使う場合には、同じ行に別のフィールドを指定できま
せん。
各フィールドへの値は、次の行に、ピクチャフィールドと同じ順番
で指定します。 値を示す式は、コンマで区切られている必要があ
ります。 式はすべて、その行が評価される前に、リストコンテキ
ストで評価されますので、1 つのリスト式が複数のリスト要素を作
るようにもできます。 式は、中括弧で括って、複数行にすること
もできます。 もし、そのようにするときは、最初の行の最初のト
ークンを、開き中括弧にしなければなりません。
"@" ではなく、"^" で始まるピクチャフィールドは、特別な扱いを
受けます。 "#" を使ったフィールドでは、値が未定義の場合に、
空白となります。 他のタイプのフィールドでは、"^" はある種の
充填モードになります。 値として指定できるものは、任意の式で
はなく、テキスト文字列が入ったスカラ変数名でなければなりませ
ん。 Perl はそのフィールドに入るだけのテキストを詰め込んで、
変数内の文字列の先頭から、その分を切り落とします。 次にその
変数が参照されるときには、残りの部分のテキストが印字できるこ
とになります。 (そうです、このことは変数自身が write() の実
行中に変更され、もとには戻らないということです。) 普通は、
テキストを矩形に表示するように、フィールドを縦に積むような形
で使われます。 一番最後のフィールドを "..." という文字列で
終わらせておくと、表示するテキストがその最後のフィールドにも
収まりきらなかったときに、そのまま "..." が出力されます。
$: (English モジュール使用時は $FORMAT_LINE_BREAK_CHARACTERS)
という変数に文字列を設定すると、出力する文字列の中に、この変
数内に設定した文字列中の 1 字が見つかったときに改行するよう
になります。
"^" フィールドを使うと可変長のレコードが作れます。 フォーマ
ットされるテキストが短ければ、行のどこかに "~" をおくことで
空行の出力をサプレスすることができます。 出力時には、"~" は
空白に変換されます。 "~" を 2 つ並べて書くと、すべてのフィ
ールドに入れられる値が尽きてしまうまで、そのピクチャ行と引数
行を繰り返して使用します。 (もし、"@" タイプのフィールドを
使うならば、与える式は永久に同じ値を出すことの無いようにしな
いといけません。)
ページ先頭フォーマットの処理はデフォルトでは、現在のファイル
ハンドル名に "_TOP" をつなげた名前のフォーマットで行なわれま
Perl manpages Last change: Release 5.0 Patchlevel 00 2
PERLFORM(1) USER COMMANDS PERLFORM(1)
す。 これは、各々のページの先頭で使われます。 perlfunc
manpage の write() の項を参照してください。
例:
# /etc/passwd ファイルについてのレポート
format STDOUT_TOP =
Passwd File
Name Login Office Uid Gid Home
------------------------------------------------------------------
.
format STDOUT =
@<<<<<<<<<<<<<<<<<< @||||||| @<<<<<<@>>>> @>>>> @<<<<<<<<<<<<<<<<<
$name, $login, $office,$uid,$gid, $home
.
# バグ報告書からのレポート
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) を自分で調整する必要がありま
す。
Perl manpages Last change: Release 5.0 Patchlevel 00 3
PERLFORM(1) USER COMMANDS PERLFORM(1)
フォーマット変数
その時点でのフォーマット名は、変数 $~ ($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";
ずっと良いでしょう !
NOTES
引数行には、(^ フィールドに対してではなく、@ フィールドに対
して) 任意の式が許容されますから、もっと込み入った処理には、
sprintf() や独自の関数などに任せることもできます。 たとえば:
Perl manpages Last change: Release 5.0 Patchlevel 00 4
PERLFORM(1) USER COMMANDS PERLFORM(1)
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 =
^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~~
$_
.
Perl manpages Last change: Release 5.0 Patchlevel 00 5
PERLFORM(1) USER COMMANDS PERLFORM(1)
$/ = '';
while (<>) {
s/\s*\n\s*/ /g;
write;
}
フッタ
$FORMAT_TOP_NAME には、その時点のページ先頭フォーマット(ヘ
ッダフォーマット)の名前が納められていますが、フッタに対して
自動的に同じことをするための、対応する機構は用意されていませ
ん。 フォーマットを評価するまでは、どのくらいの大きさになる
のかがわからないことも、大きな問題と言えます。 これは、Todo
のリストに入っています。
1 つの方法をあげておきます: 固定サイズのフッタであれば、
write() を行なう前ごとに $FORMAT_LINES_LEFT をチェックして、
必要なときにフッタを print することで、フッタを付けることが
できます。
もう 1 つ別の方法です: open(MESELF, "|-") を使って、自分自
身にパイプを open し (perlfunc manpage の open() の項を参照
してください)、常に STDOUT の代わりに MESELF に write() する
ようにします。 チャイルドプロセス側では、STDIN からの入力を
フォーマットし直して、好きな形にヘッダやフッタを整えるように
します。 簡単とは言えませんが、実行は可能です。
内部のフォーマット動作へのアクセス
フォーマット機構に対する低レベルのアクセスのため、formline()
を使い、$^A ($ACCUMULATOR) を直接アクセスすることができます。
たとえば、
$str = formline <<'END', 1,2,3;
@<<< @||| @>>>
END
print "Wow, I just stored `$^A' in the accumulator!\n";
もしくは、printf() に対する sprintf() のような write() に対
するサブルーティン swrite() を作るため:
use English;
use Carp;
sub swrite {
croak "usage: swrite PICTURE ARGS" unless @ARG;
local($ACCUMULATOR);
formline(@ARG);
return $ACCUMULATOR;
}
Perl manpages Last change: Release 5.0 Patchlevel 00 6
PERLFORM(1) USER COMMANDS PERLFORM(1)
$string = swrite(<<'END', 1, 2, 3);
Check me out
@<<< @||| @>>>
END
print $string;
のようにします。
WARNING
format の実行中には、グローバルな変数と local() で宣言された
動的スコープの変数だけが見えます。 my() で宣言された字句ス
コープの変数は、format と同じスコープにあるとはみなされず、
使用することができません。
Perl manpages Last change: Release 5.0 Patchlevel 00 7