#00 [foussin分室] ... [<<:home (index.html)] ... [<<:top (top.cgi)]
....... [<:prev (アマチュア・スタイル!)] ... [here: outf.pl] ... [フレーム解除]

アマチュア・スタイル!

[lib 03] サブルーチン・ライブラリ(関数)
outf.pl 出力ルーチン(いわゆるフォーマッタ)

updated: 2010/08/07 Sat 08:58 (JST-9)
©pablo foussin

#01 能書き: outf.pl とは
#02 能書き: outf.pl の使い方(未稿)
#03 outf.pl の主要関数
#04 outf.pl の使用例(サンプル・スクリプト)
#05 ダウンロード


[<:head #00] [here: #01] [>:next #02]

#01 能書き: outf.pl とは

outf.pl とは、greg_calc.pl に実装した &outf 関数を機能拡張した出力ルーチンで、いわゆるフォーマッタの一種。フォーマッタとは、プログラムによって生成されたデータを、ユーザーが好みの体裁で出力するための整形ルーチンの総称だ。例えば、内部表現形式のデータなどを、ユーザーが好みの体裁で出力するためには欠かせない機能といえる。

Perl は元々 sed や awk と同様、『レポート作成用言語』として利用されてきた経緯があって、format という書式制御構造を実装している。つまり Perl 自体に、フォーマッタの機能が組み込まれているわけだ。しかし、それはプレーンテキストを整形することを想定していて、html 文書の整形には適していない。html では『align属性』や『スタイルシート』を使って整形指定をし、テキスト自体は加工しない。そうなると、CGI スクリプトを使って html 文書を整形する場合、必然的に sprintf や printf を使うことになる。

outf.pl は、ぶっちゃけると sprintf を簡便に利用するためのラッパーで、『フォーマット定義関数』『置換関数』『出力関数』を一まとめにしたサブルーチン・ライブラリとなっている。独自の特殊リテラル(outfリテラル)を対象の定数値と関連付けて、ユーザーが記述したテンプレート文字列を一括置換する。


[<<:head #00] [<:prev #01] [here: #02] [>:next #03]

#02 能書き: outf.pl の使い方(未稿)

文章での説明が難しいので、執筆を断念した。


[<<:head #00] [<:prev #02] [here: #03] [>:next #04]

#03 outf.pl の主要関数

outf.pl を使うためには、まず最初に次の記述をする必要がある。

require "outf.pl";

上記の記述は必須となる。以下に主要関数の簡単(?)な書式を示す。

書式1: &outf::def($name_list, @value);
書式2: &outf::def("clear");
概要: outf リテラルの定義(登録)。
定数値 $xx と __xx (定数値リテラル)、/xx: 〜// (単位名リテラル) を関連付ける。
引数:$name_list outf リテラル名を空白文字で区切ったリストで記述する。 個々の outf リテラル名は、先頭が英字から始まる 1〜6文字の英数字(a-zA-Z0-9)でなければならない。 記述例→ 'yy1 mo1 dd1'
引数:@value $name_list のリテラル名に対応するスカラー値を指定。 スカラー値は 数値, 文字列, 式, スカラー変数, スカラー要素を指定する。
引数:"clear" グローバルハッシュ %outf::literal をクリア(初期化)する。 undef %outf::literal; を実行するだけ。
戻値: なし(voidコンテキスト)。
文例: $year=2008; $mon=6; $mday=27;
&outf::def('yy mo dd', $year, $mon, $mday);
文例の解説: &def 関数の実行によって __yy, __mo, __dd という定数値リテラルと、 /yy: 年// などの単位名リテラルが使用可能となる。これによって、 『__yy年__mo月__dd日』という文字列を『2008年6月27日』 のように置換できるようになる。
備考: リテラル名と値は、リテラル名をキーにしたハッシュ配列 %outf::literal に格納される。基本的には、グローバルのハッシュに『キー』と『値』 を代入するだけだが、$name_list は『"』『'』『,』 を記述せずにリストの指定ができるので、タイピングの手間が軽減できる。 見た目もスッキリ記述できるので、可読性が向上する。
書式1: @value = &outf::spf($type, @value);
書式2: &outf::spf($type, $name_list);
概要: 変換仕様 一括適用ルーチン(整形関数)。
ぶっちゃけ、sprintf, &short_or_full (内部関数)のラッパー
薀蓄: 変換仕様(%xx.xx)…型指定文字列、クエリ文字列、書式指定文字列、 フォーマット文字列…様々な呼び方があるが、作者は『変換仕様』 で通すことにする。『変換仕様』の出典は『LSI-C 86(試食版)』の printf のドキュメント。そこに『変換仕様』と書かれてあった… 作者はその呼称を支持することにした。『文字数が少ない』 というのが支持した理由。変換仕様は『型指定子』と 『修飾子(整形指定子)』で構成される。つまり型を変換する conversion の機能と、その型を修飾・整形する modify の機能を併せ持っている。 『呼び名』が統一できていないのは、その二面性に原因がある。
引数:$type "%xx.xx"(変換仕様) と "Xxx" 形式が指定できる。
"Xxx" 形式とは、"x", "X" の組み合わせで『文字数』『大文字』 『小文字』の指定をする(英単語専用)。"x", "X" 以外の文字は強制的に除去され、その結果が 1文字以下の文字列となった場合、デフォルトとして "Xxx" がセットされる(英略 3文字)。英語名称の文字数は 2文字(xx)、 3文字(xxx)、フルスペル(xxxx) のいずれかしか指定できない。 "Xxx" 形式の詳細は、説明書モドキの『&short_or_full』 (outf.pl の内部関数)のコメントを参照してほしい。
引数:@value $type を適用する値を指定(通常はスカラー変数のリスト)。
記述例→ $year, $mon, $mday, $hour, $min …のようなリスト。
引数:$name_list outf リテラル名を空白文字で区切ったリストで記述する。個々の outf リテラル名は、先頭が英字から始まる1〜6文字の英数字(a-zA-Z0-9) でなければならない。 記述例→ 'yy1 mo1 dd1'
戻値:@value $type 適用後の @value。
文例1(書式1): 指定の変数値の全てに "%02d" を適用。
($mon, $mday, $hour, $min, $sec) =
&outf::spf("%02d", $mon, $mday, $hour, $min, $sec);
文例2(書式1): 指定の変数値の全てに "Xxx" を適用。
$mon="january"; $wday="tuesday";
($mon, $wday) = &outf::spf("Xxx", $mon, $wday);
結果→ $mon, $wday は "Jan", "Tue" に置換される。
文例3(書式2): グローバル変数 %outf::literal の値に "%02d" を適用。
&outf::spf("%02d", "mo dd hh mi ss");
備考: 書式1 はリストコンテキスト専用となる。スカラーコンテキストなら、 sprintf を使えば済むことなので。→ $year = sprintf("%04d", $year);
リストコンテキスト以外は書式2 と判断する。void(無効)コンテキスト、 スカラーコンテキストで、尚かつ引数が 2つの時は、%outf::literal を操作対象とする。スカラーコンテキスト時の戻値は無規定(undef となる)。
$oline = &outf::conv($iline);
概要: 入力文字列に含まれる『outf リテラル』を置換して返す(出力関数)。
引数:$iline outf リテラルが記述された入力文字列(テンプレート文字列)。
outf リテラルは、事前に &outf::def で登録済でなければならない。
戻値:$oline outf リテラルが記述された入力文字列(テンプレート文字列)。
outf リテラルが置換された後の出力用文字列。 引数に outf リテラルが全く含まれていない場合は、 何もせずに $iline をそのまま戻値として返す。
文例: &outf::def("yy mo dd wd tz", 2008, 5, 26, "Mon", "JST-9");
$iline = 'Today: __yy.__mo.__dd __wd (__tz)';
$oline = &outf::conv($iline);
文例の結果: $oline は、 'Today: 2008.5.26 Mon (JST-9)' …となる。

主要関数は上記のとおり、&def, &spf, &conv の 3本だけなのだが、どうも、文章ではうまく説明できない…。


[<<:head #00] [<:prev #03] [here: #04] [>:next #05]

#04 outf.pl の使用例(サンプル・スクリプト)

例) 名前を入力すると挨拶を返すサンプル。

#!/usr/bin/perl

# "hello_test.pl"
require "outf.pl";

print 'あなたは誰? > ';
$name = <STDIN>;
chomp($name);
print "\n";

# 今日の日付を取得
($sec, $min, $hour, $mday, $mon, $year, $wd) = localtime;
++$mon;   $year += 1900;
@wname = (sunday, monday, tuesday, wednesday, thursday, friday, saturday);
$wday = $wname[$wd];

# 時間によってメッセージ(挨拶)を変える
$mes = "";
($hour > 4  and $hour < 12) && ($mes = 'おはよう!');
($hour > 11 and $hour < 19) && ($mes = 'こんにちは!');
$mes || ($mes = 'こんばんは!');

&outf::def(
    "ss mi hh dd mo yy na mes wd",
    $sec, $min, $hour, $mday, $mon, $year, $name, $mes, $wday
    );
&outf::spf("%02d", "ss mi hh dd mo");
&outf::spf("Xxx", "wd");
foreach (<DATA>) {
    chomp;
    $line = &outf::conv($_);
    print "$line\n";
}

__DATA__
今日: __yy/__mo/__dd __wd.
時刻: __hh:__mi:__ss
__mes __na さん。
お待ちしておりました。

hello_test.pl の実行例↓

G:\usr\lib\outf>hello_test.pl
あなたは誰? > foussin

今日: 2008/06/28 Sat.
時刻: 02:56:07
こんばんは! foussin さん。
お待ちしておりました。

どう? CGI スクリプトで使えそうだと思わない? 上記のサンプルは定数値リテラルだけだったので、次は単位名リテラルも使ったサンプルを考えてみる。

#!/usr/bin/perl

# "tan_test.pl"
# 単位リテラルの使用例
require "outf.pl";

@text = <DATA>;
chomp(@text);

for ($i=0; $i<3; ++$i) {
    &outf::def("ct xx", $i, $i);
    foreach (@text) {
        $line = &outf::conv($_);
        print "$line\n";
    }
}

__DATA__
__ct  type0 : __xx /xx:file#s//
__ct  type1 : __xx /xx:(真 ! (偽// !)
__ct  type2a: __xx /xx:xx<2; lily ! lilies//
__ct  type2b: __xx /:xx<2; lily ! lilies//
__ct  type3 : __xx /:xx==2; 「今、2 になりました」//

tan_test.pl の実行例↓

G:\usr\lib\outf>tan_test.pl
0  type0 :
0  type1 : 0 (偽 !)
0  type2a:
0  type2b: 0 lily
0  type3 : 0

1  type0 : 1 file
1  type1 : 1 (真 !)
1  type2a: 1 lily
1  type2b: 1 lily
1  type3 : 1

2  type0 : 2 files
2  type1 : 2 (真 !)
2  type2a: 2 lilies
2  type2b: 2 lilies
2  type3 : 2 「今、2 になりました」

ご覧のとおり、単位リテラルには type0 〜 type3 の記述方法がある。この出力例を見れば、英単語の単数形、複数形を表記できることが分かると思う。特に注目してほしいのが type0、type2a だ。これらのタイプでは、定数値が偽値になると、定数値、単位文字列もろとも除去される仕組みになっている。この機能は、次のようなシーンで利用することを想定している。

0年6か月』を 『6か月』と表示したい時…
1年0か月』を 『1年』と表示したい時…
3通のメッセージ、0通は未開封』を 『3通のメッセージ』と表示したい時…

0通は未開封』なんて、どう考えても日本語として変でしょ? outf リテラル(定数値リテラル、単位名リテラル)の詳細については、説明書モドキを参照してほしい。


[<<:head #00] [<:prev #04] [here: #05]

#05 ダウンロード

outf.pl (最新版)
$VERSION= '1.01';
$UPDATE = '2010.07.08 Thu 03:02 JST-9';
$AUTHOR = 'pablo foussin(japan)';

ソース本体を見る: (10.8 KB / sjis テキスト)
説明書モドキ(?) を見る: (40.9 KB / sjis テキスト)

ダウンロード: [ ソース本体( outf.pl )と 説明書モドキ( outf.pl.commentful.pl )のアーカイブ ]
日本語 Windows 用(sjis/crlf): outf_1.01_sjis.zip (16.2 KB)
日本語 UNIX 用(eucjp/lf): outf_1.01_eucjp.zip (16.1 KB)
Linux 用(utf8n/lf): outf_1.01_utf8n.zip (17.2 KB)
[<:head #00] ... [<<:prev (アマチュア・スタイル!)] ... [<<:home (index.html)] ... [<<:top (top.cgi)]

アマチュア・スタイル! に掲載の文書、プログラムは、 全て pablo foussin の著作物です。
ですが、プログラムについては改変自由のフリーソフトとします。