[ 英語 | 日本語 ]
Dフォーマットは文字列とDフィールドの相互変換を 指定する仕様である。 DフォーマットはDコマンドのフィールドリスト (Dintro参照) の付加情報として指定される。 文字列からDフィールドへの変換仕様を「入力」フォーマットと呼び、最も普通には DfromLine で使用するが、 Duntie および Dunpack でも使用する。 Dフィールドから文字列への変換仕様を「出力」フォーマットと呼び、最も普通には DtoLine で使用するが、 Dtie、 および Dpack でも使用する。 出力フォーマットは、一部 Dpr でも使用する。 入力および出力フォーマットは同じ構文を持つが、 意味するところは若干異なる。
入力または出力フォーマットの変換動作においては 文字列側の上にカレントポジションを仮定する。 カレントポジションは、文字列上でポジションの前にある文字の数で表す。 0ではじまる文字位置で指定すると言ってもよい。 Dフォーマットは文字のエンコーディングについて関知しないし バイトやオクテットという概念もない。
field-format-list | ::= | field-name[:format]の形式のフィールドリスト | |
format | ::= | [start] [end] [options] [repeat] [:cfmt] | |
start | ::= | absolute | relative | |
absolute | ::= | DIGITS | |
relative | ::= | +DIGITS | |
end | ::= | end-position | length | delimiter | pattern | |
end-position | ::= | -DIGITS | |
length | ::= | (DIGITS) | |
delimiter | ::= | /STRING/ | |
pattern | ::= | @STRING@ | |
options | ::= | { alignment | quoting | with-field-name }.. | |
alignment | ::= | l | r | n | |
quoting | ::= | q | x | Q | b | n | |
with-field-name | ::= | f | n | |
repeat | ::= | * | |
cfmt | ::= | scanfのフォーマットで一つだけ%をもつもの |
ここでDIGITSは"0"から"9"までの文字、 STRINGは任意の文字の列である。 (なお、 フォーマットと特殊文字 の節を参照)。
フィールドフォーマットリストを使用するコマンドには、 -t および -z の2つのコマンドオプションが使用できる。 これらのオプションは end および options の省略時値を規定する。
1つのDコマンドに2つのフィールドフォーマットリスト が指定される場合がある。 この場合、 -t および -z オプションは、双方のフィールドフォーマットリストに対して 適用される。
入力フォーマット動作は、フィールドフォーマットリストの 最初のフィールドエントリで、カレントポジション (cp)の値を0にセットして開始する。
入力スキャナーは cp を現在のフィールドエントリの start の位置にセットし、 end の位置までの文字を読み込む。 フィールドエントリに optionsが指定されている場合、 読み込みはそのオプションによってコントロールされる。 読み込み後、もしあれば cfmt による変換を行ってDフィールドを作成する。 Dフィールドの作成後、、 cp を end の仕様で決められている位置に移動する。
repeat 指定がある場合、この新しい cp から、同じフィールドエントリについての処理を繰り返す。 これは、 cp が入力文字列の終わりに達するか、 または pattern がマッチしなくなるまで繰り返される。
1フィールドエントリの処理が終わると、 入力スキャナはフィールドフォーマットリストの次のフィールドエントリに移動する。 (これはたとえ cp が入力文字列の後端に達していても終わらない)。 フィールド名がNULL文字列の場合、 フィールドはスキップされる。 (フィールドの読み込み動作は行われるが、 Dフィールドの作成は行わない)。 以上の処理が、フィールドフォーマットが終わるまで 繰り返される。
start の省略時は、 cp となる。
endの省略時動作は -t で指定された区切り字であるが、 -t のない場合、 /TAB/ (制御文字tab)が使われる。
整列オプションは固定長入力( end-position または length 指定) の場合に使用され、 先行または後続空白文字を除去する。 可変長入力( delimiter または pattern 指定)の場合、無効である。
l と r との双方が指定されている場合、 先行空白と後続空白の両方を除去する。
クォーティングオプションは可変長入力 (delimiter または pattern指定)に使用し、 区切り字をエスケープするために用いられる。 固定長入力に指定しても無効である。
q、Q、bが同時に指定された場合、 最初に現れたものが閉じるまで、他のものは無効となる。 すなわち、QUOTATION MARK (")の中では、 APOSTROPH (')やREVERSE SOLIDUS (\)は通常の文字であり、 APOSTROPH (')のなかでは、 QUOTATION MARK (")やREVERSE SOLIDUS (\)が通常の文字となる。 REVERSE SOLIDUS (\)は上記のクォーティング開始文字を通常の文字に する。オプションxは、オプションqに従属してQUOTATION MARK の中だけに有効なものであり、上記のルールに関係しない。
フィールド名付オプションは、ややトリッキーな機能である。
fオプションを使う場合、 フィールド名は入力文字列からとられるので、 フィールドフォーマットリストに書かれるフィールド名は意味を持たない。 フィールドフォーマットに書かれるフィールド名は単に無視されるので、 何を書いてもかまわない。 ただし、このような場合"."を書いておくことが推奨される。
現在の実装では、fオプションで読み込まれる文字列に 本当にCOLONがあるかどうかのチェックは行なっていない。 正しい文字列を用意するのはユーザ側の責任で行うこと。
オプション n は、カテゴリに関係なく他のオプションを無効にする。 これは、 -z オプションで有効になる省略時オプションを、個別のフィールドエントリで 無効にしたい場合に使用する。 たとえば、4つのフィールド"a"、"b"、"c"、"d" が入力行中でTABで区切られているとする。 このうちフィールド"b"、"c"、"d"を -q オプション付きで読み、フィールド"a"をオプションなしで読む指定を
-z q "a:n,b,c,d"
のように書ける。これは、次のように指定したのと同じである。
"a,b:q,c:q,d:q"
start指定が absolute または end-position のフィールドエントリに repeat は指定できない。
cfmt が指定されたとき、 読み込まれた文字列は直接Dフィールドにはならない。 指定の cfmt をフォーマットとし、 読み込まれた文字列を 入力文字列として、 C言語の関数sscanf に渡される。 cfmt には1個だけの%要素(%%を除く)を指定すること。
%要素が、%d、%o、%x、%i、 %n、%u、%f、%g、%cまたは%wc の場合、入力文字列は数値変数で受け取られ、 それを文字列に変換したものがDフィールドの値となる。 %要素が、%s, %S or %ws の場合、入力文字列は文字列として受け取られ、 それがDフィールドの値となる。
%要素が、%c、%Cまたは%wc の場合、入力文字列(ファイルコード)の最初のバイトが 整数変数で受け取られ、 その数値を文字列に変換したものがDフィールドの値となる。 これは、Dコマンドがエンコーディングを扱う唯一の例外である。
フィールドエントリにフォーマット付加情報がない場合、 省略時フィールドエントリが適用される。 (もっとも、これが大多数の場合であろう)。 上記の節に記した省略時の値が省略時フィールドエントリの値となる。 すなわち、cpをstartの値とし、-tコマンドオプションの値 (あるいは-tがなければTAB)をdelimiterの値とし、 -zコマンドオプションの値をoptionsの値とし、 あるいは-zがなければoptionsは指定なし、 そしてrepeatおよびcfmtに何も指定がないものである。
cp が入力文字列の終端にある場合、 start指定 が absolute で戻されない限り、 フィールドは読み込まれない。 しかし、これに例外がある。 次の例のように区切り字がCOMMAで、入力文字列が COMMAで始まり、COMMAで終わっているとき:
DfromLine -t "," "a,b,c"
,word,
自然な結果は次のようなものであろう。
a:
b:word
c:
しかしながら、区切り字が1文字以上の空白であった場合で、 入力文字列がCOMMAの代わりに空白で始まり、空白で終わっているとき:
-t " +" "a,b,c"
word
この場合、
a:word
という結果が自然と思われる。
この現象を一般化するために ハードデリミタとソフトデリミタという概念を導入する。
ある区切り字パターンに対して ある文字列がこの区切り字パターンにマッチするが この文字列を2つ重ねた文字列はマッチしないとき、 この文字列はこのパターンに対して「ハード」であると定義する。 2つ重ねた文字列も、同じパターンにマッチする場合、 「ソフト」であると定義する。
例を示すと、文字列","は区切り字パターン/,/にマッチする。 しかし、",,"はマッチしない。したがって、","は/,/ に対して「ハード」である。 これに対し空白1個も、空白2個も、区切り字パターン/ +/にマッチする。 したがって空白1個は、/ +/に対して「ソフト」である。
cp が入力文字列の終端にあって、その前の区切り字 (区切り字パターンにマッチした文字列)が「ハード」だった場合、 対応するフィールドエントリはNULL文字列として読み込まれる。 さらに、 cpからはじまる「ソフト」な区切り字は、読み込み前にスキップされる。 (cpから「ハード」な区切り字があった場合、NULL文字列が読み込まれる。) これらの規則は、当然であるが、 delimiter指定のフィールドエントリだけに適用される。 固定長フィールドエントリやpattern指定のフィールドエントリには関係しない。
例をあげる:
DfromLine -t " *, *| +" a,b,c,d,e
A B , ,D ,
結果:
a:A
b:B
c:
d:D
e:
入力行の先頭にある" "は、ソフトであるが、 "B"の後ろにある" , "と行の最後にある" ," とはハードであるため、このような結果になる。
入力文字列が空文字列の場合、 cp は最初から終端にいて、前の区切り字が「ソフト」か「ハード」かは 決められない。 この場合、最初のフィールドの区切り字が空列の (したがって入力文字列全体を読み込む)場合、 「ハード」を仮定し、そうでなければ「ソフト」を仮定する。 言い換えれば、空文字列を入力しても 通常ではフィールドはひとつも読み込まれない。 ただし、-t ""や://の指定によって 入力文字列全体を読み込もうとするときに限り、 値が空文字列の1フィールドが読み込まれる。
このような「ハード」、「ソフト」の定義は 数学的な精密さには欠ける。 実際、パターン",,?,?"に対し ","はソフトだが",,"はハードになるという ような奇妙な現象もおこる。 より良い「ハード」「ソフト」の定義があるかもしれない。 しかし、現在の定義は通常のケースに対し十分と思われる。 開発コストを考えると当面この定義を改良する予定はない。 (もっとも、空白列はソフトでそのほかはハードといった 単純な定義でも良いかもしれないが…)
出力動作には2つのタイプがある。 1つはDレコード順出力で、これが標準である。 もう1つはフィールドフォーマットリスト順出力で、 DtoLine の-pオプションが指定されたときに行われる。 この2つのちがいは、フィールドの出力順だけである。
Dレコード順出力では、Dレコードの最初のDフィールドをカレントフィールドとしてはじまる。 ただし、Dtieの場合はDレコードのフィールドの部分集合の最初のDフィールドからはじまる。 cpはゼロにセットされる。 出力ルーチンはフィールドフォーマットリストのカレントフィールドと同じフィールド名の エントリをさがし、 もしあれば、それをカレントフィールドエントリとして以下の出力を行う。 見つからなかった場合、省略時フィールドエントリによって出力を行う。 1フィールドの出力が終わると、Dレコードの(またはDtieの場合そのサブセットの) 次のフィールドがカレントフィールドになる。 以下同様に、Dレコードまたはそのサブセットの全Dフィールドを処理するまで続く。
フィールドフォーマット順出力では、最初にフィールドフォーマットリストの 最初のフィールドエントリをカレントフィールドエントリとする。 cpはゼロにセットする。 出力ルーチンは、Dレコードの中にその名前のフィールドがあるかどうかを探す。 見つかった場合、そのDフィールドをカレントフィールドとして出力動作が行われる。 2つ以上のDフィールドが見つかった場合、2番目のフィールドをカレントフィールドとして、 出力動作が行われる。 見つかったフィールドがすべて出力されるか、 最初から同名のフィールドが見つからなかった場合、 フィールドフォーマットリストの次のエントリにカレントフィールドリストが移動する。 この動作が、フィールドフォーマットリストの全エントリが処理されるまで続く。
カレントフィールドとカレントフィールドエントリが決まると、(もしあれば) cfmtによる変換を行い、 次いでstart指定によるcpの調整、 endによって出力する字数の調整またはdelimiterの付加を行なって出力する。 出力後 cp は出力した文字列の終端にある。
出力ルーチンレベルでの「バッファリング」は行わない。 一旦フィールドが出力されると、 cp は戻ることがない。 フィールド"b"を1-4カラムに、 フィールド"a"を6-9カラムに出力したいなら、 フィールド"b"はフィールド"a"の前に処理されるように 指定しなければならない。
省略時の start は cp からである。
出力フォーマットに pattern 指定は存在しない。
整列オプションは固定長入力( end-position または length 指定) の場合に使用され、 出力長の方が短い場合SPACEを埋め、 出力長の方が長い場合切り捨てを行う。 可変長入力( delimiter または pattern 指定)の場合、整列オプションは無効である。
出力フォーマットにおける整列オプションは互いに排他である。 ただし、 l と r との双方が指定された場合、 l が優先される。
クォーティングオプションは可変長入力 (delimiter指定)に使用し、 区切り字をエスケープするために用いられる。 固定長入力に指定しても無効である。
出力フォーマットのクォーティングオプションは互いに排他である。 ただし、これらが同時に指定された場合、 qが優先し、次にQが優先する。
n オプションは他のオプションをキャンセルする。 これは -z コマンドオプションが使われている場合、 フィールドフォーマットリストのエントリで、 それをキャンセルするために用いる。
出力フォーマットにおけるリピートは無視される。 フィールドがリピートするかどうかは、出力対象の Dレコードにフィールドが複数あるかどうかに支配され フィールドフォーマットリストに支配されるわけではない。 ただし、フォーマットがリーフフィールドリストとして 使用されるときのみリピートに意味がある。 D_lsa のマニュアルを参照。
cfmt が指定された場合、フィールドの値は出力の前に変換される。 この変換は、C言語の sprintf関数に cfmt をフォーマットとし、フィールドの値を変数として行なわれる。 cfmt には1個だけの%要素(%%を除く)を指定すること。 %要素が%d、%o、%x、%i、 %n、%u、%c、%Cまたは%wc だった場合、 フィールド値は整数変数に変換される。 %要素が%f、%gの場合フィールド値はdouble浮動小数点変数に 変換される。 %要素が%s、%Sまたは%wsの場合、フィールド値は そのまま(バイトまたはwide characterの文字列として)変数になる。 これを sprintf関数で変換し、変換された結果が出力されるべき値となる。
%wcを使用するとき、内部処理コードとして正しい値を 与えるのはユーザ側の責任である。
オプション f は cfmtとともに指定してはならない。
フィールドフォーマットリストにフォーマット付加情報のないとき、 または、フィールドエントリが見つからないとき、 省略時フィールドエントリが使われる。 これは上記の述べた省略時の値をあつめたエントリで、 cpをstartの値とし、 -tコマンドオプション(-tがなければTAB) をdelimiterとし、 -zコマンドオプションをoptionsの値とし、 -zがなければoptionsはなし、 そして、cfmtは何も指定のないものである。
シェルからDコマンドに SPACE、REVERSE SOLIDUS(\)やSOLIDUS(/)などの 文字を使うフォーマットを指定するとき、 特別に注意が必要である。
フォーマットの/STRING/中では 空白、COMMA(,)、CIRCUMFLEX ACCENT(^)、SOLIDUS(/) およびREVERSE SOLIDUS(\)の前にREVERSE SOLIDUSが必要である。 フォーマットの@STRING@の中では上記のSOLIDUSのかわりに COMMERCIAL AT(@)の前にREVERSE SOLIDUSが必要となる。
シェルとDコマンドが引数をどのように処理するかを理解することは 有用である。 入力したコマンドとその引数は、最初にシェルが空白文字で 区切る。
UNIXのシェルでは、 REVERSE SOLIDUS(\)を前に置くことによって、 あるいはQUOTATION MARK(")かAPOSTROPH(') で囲むことによって、空白文字をコマンド引数中に入れることができる。 他の特殊文字、GREATER-THAN SIGN(>)や AMPERSAND(&)なども同じクォーティング方法によって入れることができる。 ただし、 sh と csh、 また、その他のシェルで若干の差異がある。 一般的に言えば、フィールドフォーマットリスト全体を APOSTROPH(')で囲むのが安全な方法である。 ただし、フィールドフォーマット中にAPOSTROPHEのないことが条件となる。
Windowsのコマンドウィンドウシェル(cmd.exe) では、空白をコマンド引数に入れるためには QUOTATION MARK(")で囲む方法しかない。 この他の特殊文字には GREATER-THAN SIGN(>)、 VERTICAL LINE(|)、 および AMPERSAND(&)があって、 同じくQUOTATION MARKで囲むか、 あるいは CIRCUMFLEX ACCENT(^)を前に置くことによって コマンド引数中に使用できる。 CIRCUMFLEX ACCENTを引数中に使うには、 QUOTATION MARKにいれるか、二重化(^^)する。 また、PERCENT SIGN(%)も、環境変数として 解釈されうる場合にはエスケープする必要がある。 例えば、%path%はPATHディレクトリとして解釈されてしまう。 めったにこのようなことはないが、%xx%の形のコマンド引数を 使う場合、CIRCUMFLEX ACCENTを2番目の%(あるいはx) の直前につけることによってエスケープできる。 QUOTATION MARKではエスケープできないので注意すること。
これらのクォーティング文字は、引数がDコマンドに渡される前に 除去される。
シェルが引数の分割処理を行った後 フィールドフォーマットリスト引数はDコマンドで 2段階に分けて構文解析される。 第1段階はフィールドリストパージングである。 この段階では空白文字、COMMA(,)および CIRCUMFLEX ACCENT(^)が特殊な意味を持っている。 これらの特殊文字をフィールド名またはフォーマット中で使うには、 REVERSE SOLIDUSを前に置く。 パージング後、これらの文字の前のREVERSE SOLIDUSは、除去される。 他の文字の前のREVERSE SOLIDUSはそのまま残される。 なお、フィールドリスト中のCIRCUMFLEX ACCENTは、 先頭にあるとき以外は特殊な意味を持たないが、 \^はどこにあっても^"として変換される。
第2段階はフォーマットとしてのパージングである。 この段階ではSOLIDUS(/)またはCOMMERCIAL AT(@) が構文的な意味を持つ。 これらの文字をエスケープするのにもREVERSE SOLIDUSを前につける。 さらに、REVERSE SOLIDUS自身も二重化しなければならない。 (さもなければREVERSE SOLIDUSで終わる区切り字パターンを作れない)。 したがって、最終的にフォーマットパーザは、 REVERSE SOLIDUSおよびSOLIDUS(delimiterの場合) またはCOMMERCIAL AT(patternの場合) の直前のREVERSE SOLIDUSを除去する。
使用例を参照のこと。
TABで区切られたフィールド"a"、"b"、"c"を読み込む:
"a,b,c"
"csv"ファイルからフィールド"a"、"b"、"c"を読み込む:
-t "," -z q "a,b,c"
(Csv (comma separated value) フィールドははCOMMAで区切られて、 文字列フィールドではQUOTATION MARKによるクォーティングが使われる。 上記例は、先頭行からデータ行の場合。)
C言語のソースファイルからワードを読み込む:
-t "[^a-zA-Z0-9_]+" -z qQ "words:*"
行の1文字づつをフィールドとして繰り返しで読み込む。
"c:(1)*"
16進数を読み込む:
v::%x
Csvファイルへの変換(データ行のみ):
-t "," -z q
入力Dファイルには次のようなデータが入っている:
name:MIYAZAWA
point:67
point:72
point:36
ここから次のような行データに変換するには:
MIYAZAWA: 67, 72, 36
次のようなフィールドフォーマットリストを使う:
"name:/:\ /,point:/\,\ /"
(この例では、SPACEとCOMMAとがREVERSE SOLIDUSでエスケープしてある。 なお、フィールド"point"のエントリにrepeatはいらないことにも注意せよ。 また、COMMAとSPACEは各"point"フィールドの間には挿入されるが、 行の終端では入らない。)
c-formatの使用: 各値を()でくくって出力する。
value::(%s)
Dintro、 D_lsa、 DfromLine、 DtoLine、 Dtie、 Duntie、 Dpack、 Dunpack、 Dpr。
MIYAZAWA Akira