C言語勉強中 - detab問題02
- 作者: B.W.カーニハン,D.M.リッチー,石田晴久
- 出版社/メーカー: 共立出版
- 発売日: 1989/06/15
- メディア: 単行本
- 購入: 28人 クリック: 721回
- この商品を含むブログ (199件) を見る
こないだの続き。
問題
P42 演習1-20
入力されたタブを、次のタブ・ストップまでのスペースをうめる適当な数のブランク(空白)で置き換えるプログラムdetabを書け。タブ・ストップの位置は、例えばn文字というように固定して考えよ。nは変数にすべきか、記号パラメータにすべきか?
できたー!
タブ文字が一行に2個以上あるような場合、2回目以降に登場するタブ文字の位置っていうのは、前回登場したタブ文字の影響を受けてるから、単純にタブ文字の現れた位置で計算してたらおかしくなったり、それが分からなくてデバッグ用のprintfを埋め込みまくったりとか。
そんなこんなを繰り返してなんとかできました。よかったよかった。
タブ幅をコマンドラインから取得してみようと思ったのですが、文字列を数値に変換するのが大変そうだったので諦めました。
ソースコード
#include <stdio.h> #define MAXLINE 1000 // 関数のプロトタイプ宣言 void detab( char src[], char dest[], int tab_stop, int lim ); int get_tab_width( int pos, int tab_stop ); int get_line_from_stdin( char line[], int max ); void zerofill( char str[], int size ); /** * メイン */ int main( int argc, char* argv[] ) { int tab_stop = 4; // タブの幅 int line_len = -1; // 一行の文字数 char line[MAXLINE]; // 一行の文字列(変換前) char line_dest[MAXLINE]; // 一行の文字列(変換後) while( line_len != 0 ) { // 文字列変数を初期化 zerofill( line, sizeof line ); zerofill( line_dest, sizeof line_dest ); // 標準入力から一行取得してlineに入れる line_len = get_line_from_stdin( line, MAXLINE ); // lineのタブをスペースに変換してline_destに入れる detab( line, line_dest, tab_stop, MAXLINE ); // 出力する printf( "%s", line_dest ); } } /** * タブ文字を半角スペースに変換する。 * * @param src 変換前文字列 * @param dest 変換後文字列 * @param tab_stop タブ・ストップ * @param lim 変換後文字列の最大長 */ void detab( char src[], char dest[], int tab_stop, int lim ) { int src_pos = 0; // 変換前文字列の位置 int dest_pos = 0; // 変換後文字列の位置 int tab_width = 0; // タブの長さ int i = 0; // ループカウンタ // 文字列が終わるまでループ while( src[src_pos] != '\0' ) { if( src[src_pos] == '\t' ) { // タブの場合 tab_width = get_tab_width( dest_pos, tab_stop ); for( i=0; i<tab_width; i++ ) { dest[dest_pos++] = ' '; // コピー先が限界を超えたら終わり if( dest_pos > MAXLINE ) return; } src_pos++; } else { // タブ以外の場合 dest[dest_pos++] = src[src_pos++]; } // コピー先が限界を超えたら終わり if( dest_pos > MAXLINE ) return; } } /** * タブ文字の長さを計算する。 * * @param pos タブ文字の位置(行頭から数える) * @param tab_stop タブ・ストップ */ int get_tab_width( int pos, int tab_stop ) { return tab_stop - ( pos % tab_stop ); } /** * 標準入力から一行取得する。 * * @param line 取得した文字列を入れる変数 * @param max 読み込む最大文字数 * @return 読み込んだ文字数 */ int get_line_from_stdin( char line[], int max ) { int pos = 0; int i = 0; char c = 0; for( i=0; i<max-1; i++ ) { line[i] = '\0'; } while( pos < max - 1 ) { c = getchar(); if( c == EOF ) break; line[pos++] = c; if( c == '\n' ) break; } line[pos] = '\0'; return pos; } /** * 配列の要素を0で埋める。 * * @param str 配列 * @param size 配列の長さ */ void zerofill( char str[], int size ) { int i = 0; for( i=0; i<size; i++ ) { str[i] = '\0'; } }