プログラミング及び実習 6 馬青 1
例 : ファイルデータの整形 以下の ipt.dat ファイルを opt.dat ファイルに変換するプログラム ipt.dat の中の空白は空白かタブであり opt.dat の中の No と番号の間は 1 個の空白で 番号と点数の間は 1 個のタブである 2
データ ipt.dat no.1 79 no.2 73 no.3 89 no.4 67 no.5 99 opt.dat No. 1 79 No. 2 73 No. 3 89 No. 4 67 No. 5 99 3
考え方の説明 no.4 67 先頭 改行 ( 空白と見なす ) ( 空白と見なす ) 前の文字と現在の文字がすくなくともどちらか一方が空白とタブでなければ 現文字は出力する ただし 処理してから出力する 4
プログラム (1/2) #include <stdio.h> main() { int ch, fg, fgm; // fg: 現在の文字の状態 fgm: 前の文字の状態 fgm=1; // 前の文字の初期状態 ( 先頭 ): 空白かタブ while((ch=getchar())!=eof){ if(ch==' ' ch== ' t' ch==' n') fg=1; // 現文字の状態 : 空白かタブ else fg=0; // 現文字の状態 : 空白とタブでない 5
プログラム (2/2) if(fgm!= 1 fg!= 1){ /* 前と現在の文字のどちらかが空白とタブでないそういう状態のみ 現文字を出力する */ if(ch=='n') {putchar(ch-'a'+'a');} // n を N に変換して出力する else if(ch=='.') printf("%c ", ch); //. の後ろに一個の空白を入れて出力する else if (ch== ' ') putchar(' t'); // 現文字が空白なら タブで出力 else putchar(ch); // 普通の文字ならそのまま出力する } fgm=fg; // 現文字の状態を前文字の状態とする } } 6
プログラムの実行./a.out<ipt.dat>opt.dat 7
文字処理のための 標準ライブラリ関数 (1/2) 文字処理の標準ライブラリ関数を使うために #include <ctype.h> が必要である 以下の関数は全部 int 型である is*() 関数の返値が 0 でなければ 真であり 0 であれば偽である 8
文字処理のための 標準ライブラリ関数 (2/2) 関数名 機能 isdigit(ch) 0-9 の数字か islower(ch) 英小文字か isupper(ch) 英大文字か isalpha(ch) アルファ文字か ( 英小文字または英大文字か ) isalnum(ch) アルファ文字または 0-9 の数字か toupper(ch) chを大文字に変換 chが小文字でなければその値が戻される tolower(ch) chを小文字に変換 chが大文字でなければ その値が戻される 9
使用例 int ch1, ch2; ch1=getchar(); // ここで 小文字 d を入力 とする if(islower(ch1)!= 0) ch2=toupper(ch1); if(islower(ch1)) ch2=toupper(ch1); if(isalpha(ch1)==0) putchar(ch1); if(!isalpha(ch1)) putchar(ch1); if(isupper(ch1) isdigit(ch1)) putchar(ch1); else ch2=toupper(ch1); それぞれの実行結果は? 10
関数 int isdigit(ch) int isdigit(int ch) { if(ch>= 0 && ch<= 9 ) return 1; else return 0; } 11
演習問題 1 1. 標準関数 int islower(int ch) を作成しなさい 2. 標準関数 int toupper(int ch) を作成しなさい 12
演習問題 2 以下のプログラム ( 前回の例題 ) をできるだけ文字処理の標準関数を使うように修正しなさい 文字をキーボードから入力し 改行を入れた時点で 小文字を大文字 大文字 数字 改行記号はこのまま 特殊文字 ( 英数字以外の文字 ) を空白に変換して出力するプログラム ただし Ctrl+Dで終了とする 13
元のプログラム #include <stdio.h> main() { int ch; while((ch=getchar())!= EOF){ if(ch>= a && ch<= z ) // 小文字なら putchar(ch- a + A ); // 大文字に else if(ch>= A && ch<= Z ch>= 0 && ch<= 9 ch== n ) putchar(ch); // 大文字か数字か改行はそのまま else // 特殊文字なら putchar( ); // 空白に } } 14
例 : 変数名チェック 文字列データを入力し それが C 言語の変数名として適切かを調べる 使用できる文字 : ( 大小 ) 英文字 数字 アンダースコア (_) ただし 最初の文字は数字であってはならない ( 識別される文字数 : 最初から 8 文字目まで ) 出力例 : a.out 123 1 --> the first character is incorrect a23 a23 a@ a@ --> the middle character is incorrect この例題ではこのチェックなし 15
#include <stdio.h> #include <ctype.h> プログラム (1/2) main() { int ch, fg_ic=0, fg_fi=1; /* fg_ic=1: 正しくない, 0: 正しい fg_fi=1: 最初の文字 0: 他の文字 */ while((ch=getchar())!= EOF){ if(ch!= ' n'){ if(fg_fi==1 &&!isalpha(ch) && ch!= '_'){ printf("%c --> the first character is incorrect", ch); fg_fi=0; fg_ic=1; この1 文がないと どうなる? } 16
プログラム (2/2) else if(fg_ic!= 1 &&!isalnum(ch) && ch!= '_'){ printf("%c --> the middle character is incorrect", ch); fg_ic=1; } else if(fg_ic!= 1){ printf("%c", ch); fg_fi=0;} } else{ // reset fg_fi=1; fg_ic=0; printf(" n");} } // while } fg_ic という変数を導入しないとどうなる? 17
Question!isalpha(ch) (isalpha(ch)==0) 意味は??? (ch< A ch> Z ch< a ch> z ) で代替 OK? 復習 : A, B,..., Z 65-90 a, b,..., z 97-122 0,..., 9 48-57 18
第 6 回実習課題 (1/5) 1. アルファ文字または 0-9 の数字かを判断する標準関数 isalnum() と同等の機能を持つ関数 int IsAlNum(int ch) を作成し main() 関数からそれを呼び出して動作確認をするプログラム (ex06-alnum.c) を作成しなさい ただし 文字処理の標準関数は一切使わない 19
第 6 回実習課題 (2/5) 2. 以下のような文章を暗号化するプログラム (ex06-code.c) を作成しなさい (1) 1 文字ずつ読み込む ( つまり getchar() を使うこと ) (2) 英字であれば 小文字を大文字に 大文字を小文字にした上 n 字ずつずらす ただし, ずらした結果 z や Z を超える英字文字についてはずらす処理を行わない また 数字やその他はそのまま出力する (3)Ctrl-D を押さない限り 文字列を繰り返し入力可能とする 実行例 (n=3)!!n の値はプログラム内に与えるものとする $./a.out (scanf() は使わない ) This is a pen. 入力 wklv LV D SHQ. 出力 ( 暗号化結果 ) taro-x@123.ac.jp 入力 WDUR-X@123.DF.MS 出力 ( 暗号化結果 ) Ctrl-D 入力 終了 20
第 6 回実習課題 (3/5) なお 発展課題として z を 1 文字ずらしたら a になるように プログラムを改善してみてください つまり XyZ が入力された場合 (n=3 の場合 ) xyz ではなく abc で出力できるように 改善すること 21
第 6 回実習課題 (4/5) ヒント : すぐ思いつく方法は n 字ずらす を場合分けで行う b +4 x +4 1 x +4> z? を判定 a b... f... x y z??? 3a を起点に 2 で求めた距離を利用し b に対応する整数値を求め ( a +dist-1) 出力する 2 距離を計算 dist= x +4- z 22
発展課題 第 6 回実習課題 (5/5) 3. 例の変数名チェックプログラムを文字数もチェックするように つまり 8 文字を超えたなら入力文字列の代わりに the number is larger than 8 を出力するようにプログラムを改善しなさい (ex06-check.c) ただし (1)fg_fiを文字数カウントcntに変更して使うと便利かも (2) 例のプログラムはWebからコピーして使える 23