プログラミング雑技談

プログラミング雑技談

外部仕様の検討とファイルアクセス関連処理

宮坂電人
2008/4/16

1 2次のページ

テキスト変換ツールの汎用的な外部仕様

 テキスト変換ツールの基本的な構想を示します。

 手始めにテキスト変換ツールの外部仕様、つまりツールを使う側から見た仕様を考えてみましょう。コンソールからテキスト変換ツールtextConvToolを起動するとき、たいていは、

textConvTool -p パラメータ指定 ファイル指定

あるいは、

textConvTool -p パラメータ指定<標準入力指定> 標準出力指定

で「入力」「出力」「パラメータ」を指定します。

 ツール側で指定されたものを解析するのは手間なので、「Model-View-Controler」の考えで処理を分離します。

・View:「入力」「出力」「パラメータ」などの指定の取り出しと結果の表示
・Model:処理に専念

といった感じになるでしょう。

本連載は、ソフトバンククリエイティブ刊行の『C MAGAZINE』に掲載された記事を、同社の許可を得てより抜きして転載するものです。

なお、 Webでの連載として転載するに当たり、若干表現を変更している点があります(例えば「本書は」としている部分は「本連載は」としていることや図版などの省略など)。その点ご了承ください。

Model側の外部仕様

 View側は「コンソールでツールを実現する場合」と「GUIでツールを実現する場合」で大幅に内容が変化しそうなので、View側はあと回しにします。あまり見かけに左右されないModel側から仕様を固めていくことで作業がしやすくなると思われます。

 ツールのModel側(これ以降、ToolModelと呼ぶ)は処理に専念するといっても、必要な情報を外部から取り入れねばなりません。まずは、これをどう取り入れるかを決めましょう。

 パラメータとして取り込むか、あるいは何らかの呼び出し機構を用意して、それを呼び出すかは別にして、Table 1に示すようなメソッドが必要だと思われます。

Table 1  ToolModelのインターフェイス
メソッド 説明
void setOutput(byte[] iBytes); iBytesの内容を標準出力に送る
void setOutput(byte[] iBytes, int iOffset, int iSize); iBytesの内容のうちiOffsetから始まる位置よりiSizeバイトぶんを標準出力に送る
byte[] getInput(); 標準入力の内容を取り出す
Object getParam(Object iKey); iKeyで示すパラメータを取得する
java.util.Set getParamSet(); パラメータの一覧を取得する
String[] getFilenames(); ファイル名の一覧を取得する

textConvTool -p パラメータ指定 ファイル指定

で起動した状況では、getInput()を呼ぶと空っぽのbyte配列が戻り、getParam(”-p”)を呼ぶと“パラメータ指定”が戻り、getFilenames()を呼ぶとファイル指定が配列で戻る(複数のファイル指定がありうるので)というのを想像するとよいでしょう。また、

textConvTool -p パラメータ指定<標準入力指定> 標準出力指定

で起動した状況では、getInput()を呼ぶと標準入力から取り込んだ内容のbyte配列が戻り、setOutput()で標準出力に内容を書き込むことになるでしょう。

支援サブルーチンの外部仕様

 ToolModelで頻繁に使用すると考えられる処理を楽にするために、いくつかサブルーチンを用意しましょう。個々の処理を誰が処理するのかはあとで検討するとして、まずは必要になりそうな処理をTable 2にあげてみましょう。

Table 2 支援サブルーチンの外部仕様
メソッド 説明
static byte[] fileToBytes(String iFilename); iFilenameで指定のファイルの内容をbyte配列にして返す
static void bytesToFile(byte[] iBytes,
    int iOffset, int iSize, String iFilename);
iBytesの内容のうちiOffsetから始まる位置よりiSizeバイト分をiFilenameで指定のファイルとして書き出す
byte配列から1行を取り出すオブジェクト 本文のOneLinePickerの解説を参照
byte配列を構築するオブジェクト 本文のBytesBuilderの解説を参照
byteの特性を判断するサブルーチンとbyte配列の操作をするサブルーチン 本文のBytesMiscの解説を参照

 Table 2に示したもののうち、fileToBytesとbytesToFileは標準入力や標準出力が指定されていなかったときに重宝するでしょう。通常はbyte配列の読み書きで処理を記述しておき、ファイル指定があったときにfileToBytes()とbytesToFile()を使うことで簡単にファイル対応ができるはずです。

OneLinePicker

 byte配列から1行を取り出すオブジェクトのクラスです。テキスト変換では1行ずつ取り出して処理をしたい状況がありがちです。やっかいなのはOSによって改行コードが違うことがあり、これをおのおののToolModelで判断させるのは、わずらわしいだけでなくバグを誘発しやすくなります。というわけで、1行ずつ取り出す処理をクラスにします。Table 3のようなメソッドが必要になるでしょう。

 取り扱う改行コードに関しては今のところ以下の3パターンのみとします。

CR+LF(0Dh、0Ah)……主にMS-DOS、Windowsでよく使われる
CRのみ(0Dh)……主に旧MacOSでよく使われる
LFのみ(0Ah)……主にUNIX系OSでよく使われる

Table 3 OneLinePickerのメソッド
メソッド 説明
OneLinePicker(byte[] iBytes); コンストラクタ。iBytesを処理対象とする
OneLinePicker(byte[] iBytes,
    int iOffset, int iSize);
iBytesの内容のうちiOffsetから始まる位置よりiSizeバイトぶんを処理対象とするためのコンストラクタ
boolean pick(); 1行ぶんを取り出す。取り出せたならtrueを返し、そうでないならfalseを返す
byte[] getBytes(); 取り出したbyte配列を返す
int getBegin(); 取り出した1行ぶんの開始位置を返す
int getSize(); 取り出した1行ぶんのサイズを返す

BytesBuilder

 byte配列を構築するオブジェクトのクラスです。出力したいデータが元のbyte配列より大きくなることはよくあります。そこで、このクラスで作られたオブジェクトに対して出力することで、あらかじめどれだけの大きさの配列を用意するか意識しなくてよいようにします。これにはTable 4に示すようなメソッドが必要でしょう。

Table 4 BytesBuilderのメソッド
メソッド 説明
void add(byte iByte); iByteを追加する
void add(byte[] iBytes); iBytesを追加する
void add(byte[] iBytes,
   int iOffset, int iSize);
iBytesの内容のうちiOffsetから始まる位置よりiSizeバイトぶんを追加する
byte[] getAll(); 追加された全内容を返す

BytesMisc

 byteの特性を判断するサブルーチンやbyte配列の操作をするサブルーチンなどをまとめたクラスです。C言語の標準ライブラリにあるctype.hやstring.hに存在する標準関数のうち、charデータの判断、変換、コピーに使う関数のようなメソッドを用意します。今思いつくかぎりでもTable 5に示すようなメソッドが必要になるでしょう。Table 5に示したもの以外にも必要なサブルーチン的メソッドやクラスがあるかもしれませんが、とりあえずはこの範囲で次の検討作業に入ります。

Table 5  BytesMiscのメソッド
メソッド 説明
static boolean isalnum(byte iB); iBがアルファベットまたは数字ならtrueを返す
static boolean isalpha(byte iB); iBがアルファベットならtrueを返す
static boolean iscntrl(byte iB); iBが制御文字ならtrueを返す
static boolean isdigit(byte iB); iBが数字ならtrueを返す
static boolean islower(byte iB); iBが英小文字ならtrueを返す
static boolean isupper(byte iB); iBが英大文字ならtrueを返す
static boolean isxdigit(byte iB); iBが16進数文字ならtrueを返す
static boolean isCRLF(byte iB); iBが改行コードならtrueを返す
static boolean isSJISZen1st(byte iB); iBがShift JISの全角の1バイト目ならtrueを返す
static int memchr(byte[] iBA,
   int iBegin, int iSize, byte iPat);
iBAの内容のうちiBeginからiSizeバイトぶんの範囲で最初に見つかるiPatの位置を返す。見つからない場合は-1を返す
static int memcmp(byte[] iBA,
  int iBegA, byte[] iBB, int iBegB,
      int iSize);
iBAのiBegAから始まる部分とiBBのiBegBから始まる部分をiSizeぶん比較する。すべて一致すれば0を返し、一致しない場合はiBA側がiBB側より小さいならマイナス値を返し、そうでないならプラス値を返す
static void memmove(byte[] iDest, int
  iBegD, byte[] iSrc, int iBegS, int iSize);
iSrcのiBegSからiSizeぶんをiDestのiBegDから始まる部分
へコピーする
static void memset(byte[] iDest,
  int iBegD, byte iPat, int iSize);
iDestのiBegDからiSizeぶんの領域をiPatで埋める

1 2次のページ


ほかに検討すべき項目  
自分戦略研究所、フォーラム化のお知らせ

@IT自分戦略研究所は2014年2月、@ITのフォーラムになりました。

現在ご覧いただいている記事は、既掲載記事をアーカイブ化したものです。新着記事は、 新しくなったトップページよりご覧ください。

これからも、@IT自分戦略研究所をよろしくお願いいたします。