第41回
仕様設計からコーディングまで~タブ/スペース変換プログラムを作る(1)

仕様を考える

いきなり複雑な処理を取り上げると内部構造が見通しにくくなるので、まず、タブコードを指定した数のスペースに変換する――というシンプルなフィルタを作り、それを発展・改造していくことにしましょう。

スペースの数は位置によって変わる

タブストップとは、予め決められた文字の入出力位置のことです。しかし、
タブストップ幅が4であれば
タブコードを単純に4桁のスペースに変換すればよい
という訳ではありません。

タブストップ幅が4の場合、現在の入力または出力位置=文字カーソルの位置が0桁目(先頭)のときにタブコードが入れば、カーソルは4桁目に移動します。このときのタブコードは4個のスペースに置き換えなければなりません。

現在のカーソル位置が1桁目の場合も、タブコードが入ればカーソルは4桁目に移動しますが、このときのスペースは3個必要になります。

タブストップ幅とスペースの数

タブストップを「4」に設定したテキストファイルのタブを複数のスペースに置き換える――という前提で考えてみましょう。

図2のように→の箇所でタブコードが入力されたとします。

タブストップは4桁ごとの目盛りであって、ある桁位置でタブコードを入力すると、カーソルは「次のタブストップ位置」に移動します。したがって、タブが入力された位置によって、置き換えられるスペースの数は変わります。


タブ→スペースの変換式

プログラムでは、カーソルがどの位置にあっても、タブコードが見つかればそれを「次のタブストップ位置までのスペースに変換」しなければなりません。

タブストップ幅が4の場合、カーソル位置と次のタブストップ位置、カーソル位置から次のタブストップ位置までに必要なスペースの数――それぞれの関係は、表1のようになります(タブに続く文字は、カーソル位置の次の桁から出力されるものとします)。

表1:カーソルの位置と次のタブストップ位置までに必要なスペースの数
カーソル位置 次のタブ
ストップ位置
必要な
スペースの数
0 4 4
1 4 3
2 4 2
3 4 1
4 8 4
5 8 3
6 8 2
7 8 1
8 12 4
9 12 3
10 12 2
11 12 1

ここから規則性を見出せばよい訳です。すると、
「次のタブストップ位置までに必要なスペースの数」は
カーソル位置をタブストップ幅で割った余りを
タブストップ幅から引いた値
ということが分かります。

これを式にしてみましょう。

タブストップ間隔をtとし、ファイルを行の先頭から1文字ずつ読み進んでいって、n文字目でタブコードを発見した場合、次の(いちばん近い)タブストップ位置までに必要なスペースの数を求める式は、
t - (n % t)
となります。%は剰余(除算の余)を求める演算子です。

全体の動作を考える

上の式を使って、タブコードを任意の数のスペースに置き換える関数を作ってみましょう。おおよその動作は以下のようになります。

(1) ファイルの終わりまで1行ずつ読み込む

(2) 行の終わりまで先頭から1文字ずつ読み込む
  文字がタブコードなら
  → 次のタブストップまでスペースで埋める
  タブコードでなければ
  → そのままコピーする

上記の中で、(2)の部分が処理の中核部分だとわかります。この部分を独立した関数とし、(1)の部分をmain関数で処理してその中から(2)の関数を呼び出す――という形が自然でしょう。