//p60.c -- 我拆我拆..我拆拆拆! @CopyLeft by tsaiwn@cs.nctu.edu.tw // 身分證號碼檢查器與產生器 /// 建議先把身分證號碼規則弄清楚, 最好先手動檢查自己身分證號! /// 這個是讓你先有個 "該怎麼做" 的概念 /// 如果看了會寫, 阿就寫啊; 如果還是不會呢? 那就 .. 看 p61.c // 請拿那個p61.c去改, 寫入學號姓名, 並且註明最後修改時間; /// 並且在心得部分除了討論你寫的外, 也要討論從我寫的部份學到甚麼!! /// 請找有 todo 字眼的地方修改或補充就可以了 ! /// 要改其它地方也可以 :-) 目前此程式是可以 Run 的, 但不完整 // 測試時, 請故意輸入 999 或 gen 看看會怎樣? /// 學號: /// 姓名: /// Last modified date and time: /// Original creation date and time: 2010/10/17 11:15 Sunday /// Original author: tsaiwn@csie.nctu.edu.tw ////// ### rand( )在 ; is???, to??? 在 #include #include #include #include /// 用 macro 定義一些符號常數(Symbolic constant) 備用且方便改! /// 注意, Symbolic constant 一般是用全部大寫, 字_與_字間可用 _ /// 例如 以下是說以後看到 HELP 都會被compiler換成 "HELP" 這字串 #define HELP "HELP" /// 寫一些小工具函數 (utility functions)幫忙處理字串 void chop(char*); // remove tail NewLine; 去掉最尾巴的 '\n' void squeeze(char*); // remove white space; 去掉所有空白 void toUpper(char*); // pre_process it so that easy to handle /// ^^^ 包括 call squeeze 擠掉空白, 再將各字母都轉為大寫 /// /// declare functions that will be used int errCode(char*id); // error code of id, 0 means no error void pErrorMSG(char*, int); // print out error message for id char* genID(char*); // generate a valid ID int isHelp(char*), isQuit(char*), isGen(char*); // boolean function void pHelp( ); // Help message int main( ) { // 大多數 main program 都這樣開頭 int er; // for error code static char id[99]; // 不會打那麼多字吧 ! static char tmps[99]; // temporary string for id for( ;; ) { // (注意) Loop forever printf("ID checker, type ID: "); fgets(id, sizeof(id), stdin); if(feof(stdin)) break; // EOF encounted! say byebye // 用 chop 把 id 尾巴的 '\n' 咬掉 // 把 id copy 到 tmps // 可用 strcpy() 或自己寫 :-) // 把 tmps 內各字母轉為大寫 if(isQuit(tmps)) break; if(isHelp(tmps)) {pHelp( ); continue;} if(isGen(tmps)) { genID(tmps); continue; } er = errCode(tmps); // find error code of the id in tmps pErrorMSG(id, er); // pass the original input, error code } // for(;; printf("Bye bye!\nHit RETURN key ..."); getchar( ); // 企圖讀取一個 char, 讓程式停著等 User 按 RETURN 鍵 return 0; // 告知作業系統(OS)表示我們這主程式正常結束 }// main( ///////////////////////////////////////// void chop(char*p) { // remove tail '\n' ; by tsaiwn@csie.nctu if(p[0] == 0) return; // NULL string while(p[0] != 0) ++p; // 到字串結束的 NULL char; p[0]就是 *p --p; // move back to the last char if(*p == '\n') *p = 0; // remove the newLine if it is }// chop( void squeeze(char* p) { // 去掉所有空白; by tsaiwn@csie.nctu char* p2 = p; // p2 points to first char if(p[0] == 0) return; // NULL string while(*p != 0) { // Loop till end of the string if( ! isspace(*p) ) { *p2 = *p; ++p2; } //保留非空白字 ++p; // move to next char for check }// while( *p2 = 0; // 使字串結束 ! Important !!! }// squeeze( void toUpper(char*s) { int i; squeeze(s); // 擠掉空白 for(i=0; i < strlen(s); ++i) s[i] = toupper(s[i]); // library // do NOT forget to include }// toUpper int isHelp(char*p) { if(p[0] == '?') return 1; // question mark for help if( strcmp(p, HELP) == 0) return 1; //在 return 0; // 注意 strcmp 傳回 0 表示兩字串相等 } int isQuit(char*p) { // 參考 isHelp(char*p) 檢查 是否 "quit", "-1" return 0; } int isGen(char*p) { // check to see if he want to generate a ID // 參考 isHelp(char*p) 檢查 是否 "999", gen", "generate" return 0; } // isGen( /// void pErrorMSG(char*id, int e) { // the array msg[][]也可寫外面 static char msg[ ][66] ={ "OK 正確!", // 0 means OK "Letter?第一字須字母", // 1 means the first char error "Sex性別錯誤", "too short 太短了!", // 2 sex code error "too long 太長了!怎會有那麼多碼?", // 4 means too long "nonDigit? 怎會有非數字?", // contains non-digit "check code?檢查碼有問題啦!" }; // 注意尾巴要有分號 ; printf(" %s : %s\n", id, msg[e]); // e 是 error code //若嫌太簡單, 改為可印出所有查出的錯誤 .. // 可利用各 bit 代表不同 error(1, 2, 4, 8, 16, 32) // 每種錯誤用 e & (2的次方) 查看是否該印, // 當然, 這樣那個 errCode( ) 也要改; 可用 | bitwise or // 但因各 bit 獨立, 所以算 e 的時候也可用 + 取代 | }// pErrorMSG void pHelp( ) { // print Help message }// pHelp ////////////////////////// /// === a table for looking up from 'A'==> 10,.. == /// /// int yy[26]={10, 11, 12, 13, 14, 15, 16, 17, // ABCDEFGH 34, 18, 19, 20, 21, 22, 35 // I JKLMN O ,23, 24, 25, 26, 27, 28, 29 //PQRSTUV ,32, 30, 31, 33};;; // W(金門縣) X Y Z(連江縣) int a2nn(int x) { // 'A' ==> 10, 'B' ==> 11, ...可用上面 yy[ ] int i, ans=0; // this function 負責把字母轉為兩位數 // 建議先把 x 轉為大寫再處理, 可用 toupper(x) return ans; } int findCheckSum(char*s) { // compute the check sum int ans=0; // 就用這變數啦 // 先把 s[0] 轉成整數, 該整數看做兩位數, 比重各為 1, 9 // s[1] .. s[8] 要記得轉成真正的 0 .. 9 (減去 '0' 就可) // 然後其比重依序是 8, 7, 6, 5, 4, 3, 2, 1 // 各自乘上比重後, 加起來, 然後除以 10 取餘數 (就是 %10) // 用 10 減去該數, 若答案是 10 則改為 0, // 回傳該數就是了 return ans; // 回傳 check sum } int errCode(char*id) { // return error code of the id int i, len = strlen(id); // length of id // 用 isalpha( ) 查 id[0], 若有錯 return 1 if( id[1] != '1' && id[1] != '2') return 2; // error Sex // 長度太短回傳 3; 太長回傳 4 // 用 for Loop 查 s[2] .. s[9] 看有沒非數字, 可用 isdigit( ) // 只要發現有 NOT digit 則回傳 5 // 叫用 findCheckSum(id); 算出 check sum // 若該 check sum 與 id[9] 若不符合則回傳 6 /// 注意 2 與 '2' 是不同的; 2 + '0' 會等於 '2' return 0; // nothing error if we did NOT find any error :-) } // errCode char* genID(char*p) { // 依據 p[ ] 指示來產生合法 ID int i, k, c; static char newID[33] = "...not yet"; // 生好的 ID 放這 // default 也要前面兩個 char (出生地 + Sex code) // 要用到 int rand( ); 亂數函數, 宣告在 // 生出左邊從字母, 性別, 流水號 共 9 碼 // 叫用 findCheckSum(newID); 算出 檢查碼放 k; 是 0..9 喔! // newID[9] = '0' + k; // 檢查碼; 注意 '0' + 6 就是 '6' printf(" Valid ID for you: %s\n", newID); return newID; // 回傳該 id, 用不用隨你 :-) } //////////////////////////////////////////////////////////// /****** D:\testc>path c:\Dev-Cpp\bin;%path% D:\testc>gcc p61.c D:\testc>a.exe ID checker, type ID: D:\testc> **********************/