1044 火星數字 ——c實現
1044 火星數字 (20 分)
火星人是以 13 進位制計數的:
- 地球人的 0 被火星人稱為 tret。
- 地球人數字 1 到 12 的火星文分別為:jan, feb, mar, apr, may, jun, jly, aug, sep, oct, nov, dec。
- 火星人將進位以後的 12 個高位數字分別稱為:tam, hel, maa, huh, tou, kes, hei, elo, syy, lok, mer, jou。
例如地球人的數字
29
翻譯成火星文就是hel mar
;而火星文elo nov
對應地球數字115
。為了方便交流,請你編寫程式實現地球和火星數字之間的互譯。輸入格式:
輸入第一行給出一個正整數 N(<100),隨後 N 行,每行給出一個 [0, 169) 區間內的數字 —— 或者是地球文,或者是火星文。
輸出格式:
對應輸入的每一行,在一行中輸出翻譯後的另一種語言的數字。
輸入樣例:
4 29 5 elo nov tam
輸出樣例:
hel mar may 115 13
思路:
這道題和多數進位制轉換的題目看起來很相似。存在的難點是如果輸入的是火星文,可能會是一個兩個字串,因此字串的分割是難點。所以這道題的難點一是判斷輸入的是地球數字還是火星文,第二步是分割火星文字元,其三才是兩者之間的轉化。
1 判斷輸入的語言
由於火星文是字串,地球文是數字,因此看起來比較容易判斷。但是注意,由於火星文的字串之間有空格,所以有必要一次將整行全部讀完。這裡需要用到fgets()。
fgets
從檔案結構體指標stream中讀取資料,每次讀取一行。讀取的資料儲存在buf指向的字元陣列中,每次最多讀取bufsize-1個字元(第bufsize個字元賦'\0'),如果檔案中的該行,不足bufsize-1個字元,則讀完該行就結束。如若該行(包括最後一個換行符)的字元數超過bufsize-1,則fgets只返回一個不完整的行,但是,緩衝區總是以NULL字元結尾,對fgets的下一次呼叫會繼續讀該行
。函式成功將返回buf,失敗或讀到檔案結尾返回NULL。因此我們不能直接通過fgets的返回值來判斷函式是否是出錯而終止的,應該藉助feof函式或者ferror函式來判斷。fgets()在標頭檔案<stdio.h>
fgets()的典型用法如下:
fgets(buffer,n,stdin)
功能是從標準輸入裝置鍵盤(也就是stdin:stdandard input)讀入n-1個字串。由於字串結尾以"\0"結束,因此必須留出一個,也就是隻能讀入n-1個。buffer可是是提前定義好的陣列的指標,也就是陣列名。
用這種方法可以一次將一行輸入全部讀入buffer快取。但是還沒有進行賦值,因此下面還要將讀入的資訊用於賦值和判斷。更準確地說,是進行判斷和賦值,因此只有先判斷清楚輸入的是火星文還是地球文,才能決定下面怎麼賦值。比如,這裡先判斷讀到的是不是數字,可以用<ctype.h>中的isdigit()函式來進行判斷,如果讀到的是數字,就要進行賦值,然後從數字轉換到火星文。如果讀到的是火星文,也要轉換到地球文。
注意,這裡賦值不能再用scanf()函式,因為scanf會讀入下一個輸入,而非目前讀進到buffer中的輸入。這裡需要用到能將已經讀入快取的資料進行賦值操作,這個函式是sscanf()。百度介紹如下:
sscanf與scanf類似,都是用於輸入的,只是後者以鍵盤(stdin)為輸入源,前者以固定字串為輸入源。sscanf()在標頭檔案<stdio.h>
例如:
sscanf("1 2 3","%d %d %d",buf1, buf2, buf3); 成功呼叫返回值為3,即buf1,buf2,buf3均成功轉換。
sscanf("1 2","%d %d %d",buf1, buf2, buf3); 成功呼叫返回值為2,即只有buf1,buf2成功轉換。
(注意:此處buf均為地址)
1、一般用法
1
2
3
char
buf[512] = ;
sscanf
(
"123456 "
,
"%s"
, buf);
printf
(
"%s\n"
, buf);
結果為:123456
2. 取指定長度的字串。如在下例中,取最大長度為4位元組的字串。
1
2
sscanf
(
"123456 "
,
"%4s"
, buf);
printf
(
"%s\n"
, buf);
結果為:1234
3. 取到指定字元為止的字串。如在下例中,取遇到空格為止字串。
1
2
sscanf
(
"123456 abcdedf"
,
"%[^ ]"
, buf);
printf
(
"%s\n"
, buf);
結果為:123456
4. 取僅包含指定字符集的字串。如在下例中,取僅包含1到9和小寫字母的字串。
1
2
sscanf
(
"123456abcdedfBCDEF"
,
"%[1-9a-z]"
, buf);
printf
(
"%s\n"
, buf);
結果為:123456abcdedf
5. 取到指定字符集為止的字串。如在下例中,取遇到大寫字母為止的字串。
1
2
sscanf
(
"123456abcdedfBCDEF"
,
"%[^A-Z]"
, buf);
printf
(
"%s\n"
, buf);
結果為:123456abcdedf
6、給定一個字串iios/[email protected],獲取 / 和 @ 之間的字串,先將 "iios/"過濾掉,再將非'@'的一串內容送到buf中
1
2
sscanf
(
"iios/[email protected]"
,
"%*[^/]/%[^@]"
, buf);
printf
(
"%s\n"
, buf);
結果為:12DDWDFF
7、給定一個字串"hello, world",僅保留"world"。(注意:“,”之後有一空格)
1
2
sscanf
(
"hello, world"
,
"%*s%s"
, buf);
printf
(
"%s\n"
, buf);
結果為:world
P.S. %*s表示第一個匹配到的%s被過濾掉,即hello被過濾了,
如果沒有空格則結果為NULL。 [2]補充知識:
%[a-z] 表示匹配a到z中任意字元,貪婪性(儘可能多的匹配)
%[aB'] 匹配a、B、'中一員,貪婪性
%[^a] 匹配非a的任意字元,並且停止讀入,貪婪性
這樣就可以完整的讀入一行資訊並準確的進行賦值操作。
2 分割火星文字元
由於地球文只是數字無需轉化。火星文之間有空格,因此注意要將火星文斷開。這裡要用到strtok()函式。百度介紹如下:
strtok
分解字串為一組字串。s為要分解的字元,delim為分隔符字元(如果傳入字串,則傳入的字串中每個字元均為分割符)。首次呼叫時,s指向要分解的字串,之後再次呼叫要把s設成NULL。strtok()在標頭檔案<string.h>
原型 char *strtok(char s[], const char *delim);
功能
分解字串為一組字串。s為要分解的字串,delim為分隔符字串。
例如:strtok("abc,def,ghi",","),最後可以分割成為abc def ghi.尤其在點分十進位制的IP中提取應用較多。
常用功能是這樣的:
第一次可以將s的指標傳進去,第二次就需要將指標置為NULL。所以常用寫法如下:
str1=strtok(line," \n"); str2=strtok(line," \n");
例項:
#include <string.h> #include <stdio.h> int main(void) { char input[16]="abc,d"; char*p; /*strtok places a NULL terminator in front of the token,if found*/ p=strtok(input,","); if(p) printf("%s\n",p); /*A second call to strtok using a NULL as the first parameter returns a pointer to the character following the token*/ p=strtok(NULL,","); if(p) printf("%s\n",p); return 0; }
輸出為:
abc
d
利用上述例項中的方法就可以斷開輸入的火星文字串。由於火星文可能只有一個字串,比如整20——hel。因此建議寫成如下格式:
strtok(line," \n");
strtok(NULL," \n");
3 火星文與地球文之間的轉化
地球文轉到火星文比較簡單,取出對應的高低位,在陣列中查詢即可。由於有了前兩步的基礎,火星文轉地球文也比較簡單,只需要將截斷之後的火星文在建立的火星文字串陣列中遍歷即可,在乘以對應的進位制。
完整程式碼:
//1044 火星數字 V1
#include <stdio.h>
#include <ctype.h>
#include <string.h>
char *units[]={"tret","jan","feb","mar","apr","may","jun","jly","aug","sep","oct","nov","dec"};
char *tens[]={"tam","hel","maa","huh","tou","kes","hei","elo","syy","lok","mer","jou"};
int Mars2Earth(char *s){
if(s){
int i;
for(i=0;i<13;i++){
if(strcmp(s,units[i])==0) return i; //個位數字
}
for(i=1;i<13;i++){
if(strcmp(s,tens[i-1])==0) return i*13; //高位數字
}
}
return 0;
}
int main(){
int n,m,i;
char line[11];
fgets(line,11,stdin);
sscanf(line,"%d",&n);
for(i=0;i<n;i++){
fgets(line,11,stdin);
if(isdigit(line[0])){ //input is num
sscanf(line,"%d",&m);
if(m/13&&m%13) printf("%s %s\n",tens[m/13-1],units[m%13]);
if(m/13&&m%13==0) printf("%s\n",tens[m/13-1]);
if(m/13==0) printf("%s\n",units[m%13]);
}
else{ //input is char
m=Mars2Earth(strtok(line," \n"));
m+=Mars2Earth(strtok(NULL," \n"));
printf("%d\n",m);
}
}
return 0;
}