macroscope

( はてなダイアリーから移動しました)

わたしがよくつかうデータ形式 (2) テキストファイル、空白くぎり 兼 フィールド長固定

【まだ書きかえます。どこをいつ書きかえたかを必ずしも明示しません。】

- 0 -
[第1部]のつづき。[わたしがAwkで扱う「物理的」標準データ形式: 表を表現する空白区切りのテキストファイル] を改訂・補足したものである。

- 1 -
計算機であつかわれるデータにはテキストデータとバイナリデータがあるとされることがあるが、ディジタル計算機があつかうデータはすべてビット列ではあるから、その全部をバイナリデータというべきで、テキストデータはその部分集合だろう。

ここでは「テキストファイル」を、なんらかの文字コード体系のもとでの図形文字 (printable character、印字可能文字) と改行コード [注] だけをふくみ、その他の制御コードや未定義のコードをふくまないファイル、だとする。それは、改行コードによってくぎられた「行」のあつまりとして認識される。行は図形文字がならんだものである。 (ここで、空白は図形文字にふくめておく。)

  • [注] 改行コードは、論理的には1種類の制御コードであるべきだ。ところが現実には、LF (line feed, ASCII 16進 0A) と CR (carriage return, ASCII 16進 0D) がある。もともと、タイプライターで (横書きを前提として)、CRは印字ヘッドの横位置を行頭にもどすこと、LFは紙を縦に1行ぶん進めることをさしていた。計算機上のテキストファイルの改行コードは、Unix では LF の1バイトだが、MS-DOS では CR LF の2バイトであり MS Windows でもそれがひきつがれていることが多い。Unix準拠になるまえの MacOS では CR の1バイトがつかわれていた。複数のOSや編集ソフトウェアを経由すると、改行コードが首尾一貫しないファイルができる可能性がある。

- 1X -
1節でのべたテキストファイルの定義は、Unixでのファイルのあつかいが事実上の標準になってからのものである。

1980年代にはそうではなく、わたしはテキストデータをつぎのようなファイル形式であつかったことがある。

  • 固定長形式 ... 改行コードはふくまれていない。一定バイト数 (標準はカード由来の80バイト) ごとに行とみなす。行末は、空白でない最後の文字までを有効とし、あとの空白は無視する。
  • 可変長形式 ... まず行の長さ (バイト数) がしめされ、そのあとに行の実体が続く。行長をあらわすものが1バイト符号なし整数ならば、あらわせる行長は255バイト以下である。

- 2 -
第1部で論じたような表形式のデータを表現するためには、それぞれの行がフィールド(field)にくぎられる必要がある。(複数の行にまたがって同じ番号のフィールドをつないだものが列である。)

たとえば、Awk 言語では、入力データを1行読みこむごとにそれをフィールドに分割する。そのとき、FS という組みこみ変数がつかわれる。その意味は field separator である。FSに文字列が指定されていれば、その文字列の前後が別々のフィールドとして認識される。(Awk で FS が指定されなかったときは、空白とタブの両方が有効である。ただし、空白のあつかいについては注意が必要だ。あとの 2c 節でのべる。)

- 2a -
(Awkではふつうでないのだが) 世の中でフィールドくぎり文字としてよくつかわれているのは、コンマ(「,」)である。コンマくぎりのテキストファイルは「CSV」(comma-separated value の略)といわれ、表計算ソフトウェア間のデータ交換では事実上の標準になっている。

この形式の問題点としては、まず、フィールドの中に (文字列の部分として) コンマをふくんでいて、それをフィールドくぎりとみなしてほしくないばあいがある。その標準的対策は、引用符(「"」) でくくることである。ところが、こんどは、つたえたい内容に引用符をふくんでいるばあいはどうするか、という問題が生じる。それぞれのソフトウェアごとに約束がきめられている。

【Awkで読むときは、FSに "," を指定すると、文字列の中のコンマもフィールドくぎりとみなしてしまう。文字列の部分として読みたければ、フィールドにわけないで行全体を文字列として読み、解読する必要がある。わたしはそのためのプログラムを組み、Awkの教材の[コンマ区切りのデータ] で紹介した。】

もうひとつ、フィールドの中に改行をふくむことができるか、という問題がある。わたしは、行のきれめのほうがフィールドのきれめよりも大きなきれめだと思っているので、フィールドの中に改行はないと考えたい。ところが、表計算ソフトウェアではセルの中に改行をふくめることができ、そのままCSVで書き出すと、セルの内容の途中で行がかわるファイルができる。【これは上記のAwkプログラムでうまく読めない。】

- 2b -
もうひとつ、よくつかわれているのは、タブくぎりである。TAB (ASCII 07) は制御コードなので、この記事の第1節でいうテキストファイルからははずれるが、世の中ではタブをふくむものもテキストファイルとみなされることが多い。

わたしは、タブくぎりは、「フィールドくぎり文字がかならずタブ、タブがかならずフィールドくぎり文字」という状況にかぎって、便利だと思う。対象となるファイルに人がエディタなどで手をつけることが絶対になく、データを書くのも読むのもあらかじめ決められた計算機プログラムだけでおこなわれるならば、よいかもしれない。企業や役所のルーチンワークならばそういうことが多いのだろうと思うが、研究や大学教育ではそれをまもるのはむずかしいと思う。

タブがふくまれたテキストファイルを、計算機のコンソール画面 [注] やテキストエディタ上にすなおに表示すると、タブはいくつかの空白と同じように見える。そして、ひとつのタブがいくつの空白に見えるかは、行の中でタブの置かれた場所によってちがう。そういうファイルを人がエディタで編集すると、タブがいくつかの空白に化けてしまうおそれがある。そうするとタブくぎりとしては正しくなくなる。

  • [注] MS Windowsの「コマンド プロンプト」、X Window System の xterm などの「端末」、Rの R Console などを想定している。そこではデータが文字列として表示される。そのうち (すくなくとも) ASCII 文字は固定幅で表示される。

わたしは、空白に見えるものは実際に空白であってほしいので、人が編集する可能性のあるデータファイルからは、タブを排除したい。

- 2c -
空白をフィールドくぎりにすることもある。

このばあい最大の問題は、複数の空白がならぶばあいのあつかいだ。複数の空白がならぶとき、何個の空白があるかを見わけることはむずかしい。とくにフォント幅が可変ならばわからない。フォント幅が固定ならばよく見ればわかるが、注意が必要だ。

そこで、「複数の連続した空白はひとつの空白と同等とみなされる」というあつかいがふつうになっている。Awkで FSをとくに指定しなかったばあい、空白とタブの両方がフィールドくぎり文字になるが、タブは1個ずつそれぞれ有効なのに対して、連続した空白は1個のくぎり文字とみなされる。

このような約束をした空白くぎりでは、内容が空 (長さ0の文字列) であるフィールドを表現することができない。実質的に空であるとしても、なんらかの図形文字による表現におきかえないといけない。

コンマくぎりの場合と同様に、フィールドの内容の 文字列のうちに空白があったらどうするかという問題がある。対策としては、2a でのべたのと同様に、引用符でくくることがある。(Awkでは、FS によるフィールド分割にたよれず、行全体を解読する必要がある。) 別の対策としては、文字列に空白をそのままふくめるのをあきらめ、あらかじめ別の文字 (たとえば下線文字「_」) におきかえておくことがある。(もとから下線文字があることもありうるならば、それとの区別の約束も必要になる。)

- 3 -
わたしは、第1部でのべたような表のデータを、コンソール画面やエディタで、列が縦にそろっている形で見たい。

(空白もふくめた) 文字セットのフォント幅が一定ならば、これは、各列ごとに、文字数を一定 (どの行でも同じ) にすることによって達成できる。

ひとまず1文字1バイトのばあいを想定し、「文字数」と「バイト数」を区別しないことにする。

Fortranの書式つき(formatted)入出力では、書式 (format) の中で各フィールドがつかう文字数を指定している。同じ書式を使いつづけて各行を読み書きすれば、列は縦にそろう。なお、Fortranの書式つき入出力ではフィールドくぎり文字はつかわない。各フィールドの文字数を必要最小限に設定していると、となりどうしの列の文字列がつながってしまい、空白くぎりとしては正しく読めないことがある。書式つきで書きだして、空白くぎりとして読む可能性もあるのならば、書くときの書式に明示的に(「1X」などの形で) 空白を入れておくか、または、フィールドごとの文字数を余裕をもたせてあたえる必要がある。

AwkやCでは printf で書式を指定して、これと同様な形で書き出すことができる。

なお、Fortran 77 以後の Fortran には、「ならびにしたがう」(list-directed) 入出力がある。プログラム上の表現としては、formatのかわりに「*」を書く。これで数値データを読ませるときは、データは空白くぎりにしておけばよい。文字列データを読ませるときは、データの文字列が引用符でくくられている必要があるらしい。

わたしは、同じデータを、画面上で目でみることもあり、Fortran であつかうことも、Awk であつかうこともあるので、データを、フィールド長固定でもあり、空白くぎりでもある形にしたい。

実際には、データに、長さがさだまらない文字列をふくめたいことがある。そのようなフィールドは、最後 (右端) にもってくる。そうすれば、その手まえまでのフィールドは、縦にそろえることができる。最後のフィールドだけはフィールド長可変になる。

- 4 -
日本語文字がはいるばあいも、ASCIIのフォントの文字幅が一定で、漢字・かなのフォントの文字幅が ASCII のフォントの文字幅のちょうど2倍ならば、縦をそろえることができる。しかも、文字コードが、Shift_JIS あるいは 日本語EUC ならば (そして内容が JIS漢字の (古い表現だが) 第一・第二水準の字ならば)、日本語の1文字は2バイトで表現されるので、ASCIIと日本語文字がまざっても、画面でしめる幅とデータの長さ (バイト数) とは対応する。

日本語文字の字数のちがいを、その差の2倍のASCIIの空白を入れることによって、そろえることができる。

- 5 -
しかし、国際化の時代になって、4節の前提がくずれてきた。アラビア文字、インド系文字など、文字幅一定で表示できない文字もある。また、日本語文字も文字コード UTF-8 で表現されることがふえてきた。UTF-8 では、1文字のバイト数は一定でないが、ASCII文字は1バイト、日本語文字はだいたい3バイトなので、画面でしめる幅とバイト数とが対応しなくなった。

この状況でも、わたしは縦の列をそろえたいのだが、その対象を、今後は ASCIIで書ける情報にかぎったほうがよさそうだと思うようになった。ASCII の文字幅固定のフォントは、ソースプログラムの縦をそろえたい需要はあるので、今後もエディタなどで利用可能だろう。しかしASCIIと日本語文字とが「半角、全角」の関係にあることはつづかないかもしれない。

3節の最後にのべたように、最後(右端)のフィールドに文字列を置くばあいには、そのうちに日本語文字があってもよい。