前回までのコードはこちら。
初期コード
#include <stdio.h>
const int SMALL_A = 97;
const int SMALL_M = 109;
const int SMALL_N = 110;
const int SMALL_Z = 122;
const int LARGE_A = 65;
const int LARGE_M = 77;
const int LARGE_N = 78;
const int LARGE_Z = 90;
const int ENCRYPT_NUMBER = 13;
enum ModeFlag {
ENCRYPT = 0,
DECRYPT = 1,
EXIT = 2
};
int main(void) {
char inputCharactors[1000];
char outputCharactor;
int i = 0;
int modeFlag;
printf("暗号作成の時は0を\n暗号解読のときは1を\n終了するときは2を入力してください:");
scanf("%d",&modeFlag);
if (modeFlag == ENCRYPT || modeFlag == DECRYPT) {
if (modeFlag == ENCRYPT)
printf("暗号化させたい文を入力してください\n");
else
printf("解読させたい文を入力してください\n");
scanf("%s",inputCharactors);
while (inputCharactors[i] != '\0') {
if (inputCharactors[i] >= LARGE_A && inputCharactors[i] <= LARGE_M)
outputCharactor = inputCharactors[i] + ENCRYPT_NUMBER;
else if (inputCharactors[i] >= LARGE_N && inputCharactors[i] <= LARGE_Z)
outputCharactor = inputCharactors[i] - ENCRYPT_NUMBER;
else if (inputCharactors[i] >= SMALL_A && inputCharactors[i] <= SMALL_M)
outputCharactor = inputCharactors[i] + ENCRYPT_NUMBER;
else if (inputCharactors[i] >= SMALL_N && inputCharactors[i] <= SMALL_Z)
outputCharactor = inputCharactors[i] - ENCRYPT_NUMBER;
else outputCharactor = inputCharactors[i];
printf("%c", outputCharactor);
i++;
}
i = 0;
}
else if (modeFlag == EXIT)
return 0;
else
printf("正しい数字を入力してください(怒)");
printf("\n");
}
結構プログラムの内容がパッと見ただけで分かるようになってきたのではないかと思う。
正直、プログラミングの初心者である学生がここまで考えて課題を提出してきたら加点するレベル。
ただ、私は社会人でプログラマとしてやってきてまださらに改良点が思いつくらしい。
学生時代のプログラムから相当な成長を感じる。
今回も表題にある通り、処理の共通化について記載していく。
事前準備
37行目以降にある暗号化処理部を今回の内容解説しやすいように一部アルゴリズムの見直しを行う。
プログラム上ではA~Mは+13, N~Zは-13としていたが、英単語26文字の割った余りと等しくなるため、そちらを採用する。
変更前
if (inputCharactors[i] >= LARGE_A && inputCharactors[i] <= LARGE_M)
outputCharactor = inputCharactors[i] + ENCRYPT_NUMBER;
else if (inputCharactors[i] >= LARGE_N && inputCharactors[i] <= LARGE_Z)
outputCharactor = inputCharactors[i] - ENCRYPT_NUMBER;
else if (inputCharactors[i] >= SMALL_A && inputCharactors[i] <= SMALL_M)
outputCharactor = inputCharactors[i] + ENCRYPT_NUMBER;
else if (inputCharactors[i] >= SMALL_N && inputCharactors[i] <= SMALL_Z)
outputCharactor = inputCharactors[i] - ENCRYPT_NUMBER;
変更後
if ((input >= LARGE_A && input <= LARGE_Z)) {
outputCharactor = (input - LARGE_A + ENCRYPT_NUMBER) % 26 + LARGE_A;
} else if ((input >= SMALL_A && input <= SMALL_Z)) {
outputCharactor = (input - SMALL_A + ENCRYPT_NUMBER) % 26 + SMALL_A;
}
処理の共通化
さて、本題に入る。
普段からコピー&ペーストは使っているだろうか。
文章を書く際はWindowsなら「Ctrl + C」「Ctrl + V」、Macなら「⌘ + C」「⌘ + V」は欠かせないだろう。
果たしてプログラムを書く際もコピー&ペーストすることは良いことなのだろうか。
if ((input >= LARGE_A && input <= LARGE_Z)) {
outputCharactor = (input - LARGE_A + ENCRYPT_NUMBER) % 26 + LARGE_A;
} else if ((input >= SMALL_A && input <= SMALL_Z)) {
outputCharactor = (input - SMALL_A + ENCRYPT_NUMBER) % 26 + SMALL_A;
}
おそらくここの部分は結構コピーしがちなコードな気がする。
全体コピーして、変更すべき対象であるLARGE_Aの定数部分を対象に変更するような書き方を私の学生時代もやっていたと思う。
だが、ここで機能を修正する必要がある場合はどうするか。
コピペした先を1つ1つ探して地道に修正する作業が始まる。。
コピペ先を1つでも見逃すと修正ミスでエラーになったり誤作動になることが予想される。
それではどのように解決するかというときに、表題にもある処理の共通化をおこなう。
char encryptCore(char input, int baseCharactor){
return (input - baseCharactor + ENCRYPT_NUMBER) % 26 + baseCharactor;
}
char encrypt(char input) {
if ((input >= LARGE_A && input <= LARGE_Z)) {
return encryptCore(input, LARGE_A);
} else if ((input >= SMALL_A && input <= SMALL_Z)) {
return encryptCore(input, SMALL_A);
}
return input;
}
ポイントとしては、基本的に下記2点を意識すれば良いと思う。
- 共通の部分を括り出してメソッド化する
- 共通でない部分を引数とおく
今回は入力文字を26で割ることは共通なのでそこを残し、LARGE_A, SMALL_Aで足し引きする値は共通でないので引数とした。
これによって、例えば英語の文字がこれから1文字増えて27文字になりました!!!となっても変更する部分は26と記載している部分をいじれば、ほぼ修正完了になるだろう。
コピペしているコードを共通化しよう。
ポイントは1. 共通の部分をメソッド化、2. 共通でない部分は引数化すること。
最後に今回のまとめのコードを記載する。
次はそろそろこのコードでは厳しくなってきたのでサンプルコードを変えようかな。
変更後コード
#include <stdio.h>
const int SMALL_A = 97;
const int SMALL_Z = 122;
const int LARGE_A = 65;
const int LARGE_Z = 90;
const int ENCRYPT_NUMBER = 13;
const int ALPHABET_COUNT = 26;
enum ModeFlag {
ENCRYPT = 0,
DECRYPT = 1,
EXIT = 2
};
char encryptCore(char input, int baseCharactor){
return (input - baseCharactor + ENCRYPT_NUMBER) % ALPHABET_COUNT + baseCharactor;
}
char encrypt(char input) {
if ((input >= LARGE_A && input <= LARGE_Z)) {
return encryptCore(input, LARGE_A);
} else if ((input >= SMALL_A && input <= SMALL_Z)) {
return encryptCore(input, SMALL_A);
}
return input;
}
int main(void) {
char inputCharactors[1000];
char outputCharactor;
int i = 0;
int modeFlag;
printf("暗号作成の時は0を\n暗号解読のときは1を\n終了するときは2を入力してください:");
scanf("%d",&modeFlag);
if (modeFlag == ENCRYPT || modeFlag == DECRYPT) {
if (modeFlag == ENCRYPT)
printf("暗号化させたい文を入力してください\n");
else
printf("解読させたい文を入力してください\n");
scanf("%s",inputCharactors);
while (inputCharactors[i] != '\0') {
outputCharactor = encrypt(inputCharactors[i]);
printf("%c", outputCharactor);
i++;
}
i = 0;
}
else if (modeFlag == EXIT)
return 0;
else
printf("正しい数字を入力してください(怒)");
printf("\n");
}