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
这道题和多数进制转换的题目看起来很相似。存在的难点是如果输入的是火星文,可能会是一个两个字符串,因此字符串的分割是难点。所以这道题的难点一是判断输入的是地球数字还是火星文,第二步是分割火星文字符,其三才是两者之间的转化。
由于火星文是字符串,地球文是数字,因此看起来比较容易判断。但是注意,由于火星文的字符串之间有空格,所以有必要一次将整行全部读完。这里需要用到fgets()。
fgets
从文件结构体指针stream中读取数据,每次读取一行。读取的数据保存在buf指向的字符数组中,每次最多读取bufsize-1个字符(第bufsize个字符赋'\0'),如果文件中的该行,不足bufsize-1个字符,则读完该行就结束。如若该行(包括最后一个换行符)的字符数超过bufsize-1,则fgets只返回一个不完整的行,但是,缓冲区总是以NULL字符结尾,对fgets的下一次调用会继续读该行。函数成功将返回buf,失败或读到文件结尾返回NULL。因此我们不能直接通过fgets的返回值来判断函数是否是出错而终止的,应该借助feof函数或者ferror函数来判断。fgets()在头文件
fgets()的典型用法如下:
fgets(buffer,n,stdin)
功能是从标准输入设备键盘(也就是stdin:stdandard input)读入n-1个字符串。由于字符串结尾以"\0"结束,因此必须留出一个,也就是只能读入n-1个。buffer可是是提前定义好的数组的指针,也就是数组名。
用这种方法可以一次将一行输入全部读入buffer缓存。但是还没有进行赋值,因此下面还要将读入的信息用于赋值和判断。更准确地说,是进行判断和赋值,因此只有先判断清楚输入的是火星文还是地球文,才能决定下面怎么赋值。比如,这里先判断读到的是不是数字,可以用
注意,这里赋值不能再用scanf()函数,因为scanf会读入下一个输入,而非目前读进到buffer中的输入。这里需要用到能将已经读入缓存的数据进行赋值操作,这个函数是sscanf()。百度介绍如下:
sscanf与scanf类似,都是用于输入的,只是后者以键盘(stdin)为输入源,前者以固定字符串为输入源。sscanf()在头文件
例如:
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/12DDWDFF@122,获取 / 和 @ 之间的字符串,先将 "iios/"过滤掉,再将非'@'的一串内容送到buf中
1
2
sscanf
(
"iios/12DDWDFF@122"
,
"%*[^/]/%[^@]"
, 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的任意字符,并且停止读入,贪婪性
这样就可以完整的读入一行信息并准确的进行赋值操作。
由于地球文只是数字无需转化。火星文之间有空格,因此注意要将火星文断开。这里要用到strtok()函数。百度介绍如下:
strtok
分解字符串为一组字符串。s为要分解的字符,delim为分隔符字符(如果传入字符串,则传入的字符串中每个字符均为分割符)。首次调用时,s指向要分解的字符串,之后再次调用要把s设成NULL。strtok()在头文件
原型 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
#include 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");
2018.12.07
也可以完全没必要这么麻烦。因为输入的数字是[0,169),因此用火星文表示不会是三个单词,这就为如何断句提供了方便。因为高位都是三个字母的,低位有3个和4个字母的。所以如果不是数字,直接判断长度就可以啦。
注意事项:
1、注意火星文的13只是一个tam,26只是一个hel。所以如果是两个位的话,要根据%13之后的余数是否为0,判断转换为火星文之后是有两个单词,还是一个单词。
2、只要在读入N之后用一个getchar()就好。for循环中不需要用getchar(),否则会出现错误。
这种思路也比较简单,见代码2.
地球文转到火星文比较简单,取出对应的高低位,在数组中查找即可。由于有了前两步的基础,火星文转地球文也比较简单,只需要将截断之后的火星文在建立的火星文字符串数组中遍历即可,在乘以对应的进制。
完整代码:
代码1
//1044 火星数字 V1
#include
#include
#include
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
代码2
#include
#include
#include
using namespace std;
int main(){
int n; cin>>n;
string diwei[13]={"tret","jan","feb","mar","apr","may","jun","jly","aug","sep","oct","nov","dec"};
string gaowei[12]={"tam","hel","maa","huh","tou","kes","hei","elo","syy","lok","mer","jou"};
getchar();
for(int i=0;i=13){ // >=13
if(num%13!=0){
ans[0]=diwei[num%13];
num/=13;
ans[1]=gaowei[num%13-1];
cout<4){ // two numbers of mars
string s1,s2; s1=s.substr(0,3) ; s2=s.substr(4);
int i,j;
for(i=0;i<12;i++) if(s1==gaowei[i]) break;
for(j=0;j<13;j++) if(s2==diwei[j]) break;
cout<<(i+1)*13+j<