问题
问题描述
请你写一个命令行分析程序,用以分析给定的命令行里包含哪些选项。每个命令行由若干个字符串组成,它们之间恰好由一个空格分隔。这些字符串中的第一个为该命令行工具的名字,由小写字母组成,你的程序不用对它进行处理。在工具名字之后可能会包含若干选项,然后可能会包含一 些不是选项的参数。
选项有两类:带参数的选项和不带参数的选项。一个合法的无参数选项的形式是一个减号后面跟单个小写字母,如"-a" 或"-b"。而带参数选项则由两个由空格分隔的字符串构成,前者的格式要求与无参数选项相同,后者则是该选项的参数,是由小写字母,数字和减号组成的非空字符串。
该命令行工具的作者提供给你一个格式字符串以指定他的命令行工具需要接受哪些选项。这个字符串由若干小写字母和冒号组成,其中的每个小写字母表示一个该程序接受的选项。如果该小写字母后面紧跟了一个冒号,它就表示一个带参数的选项,否则则为不带参数的选项。例如, "ab:m:" 表示该程序接受三种选项,即"-a"(不带参数),"-b"(带参数), 以及"-m"(带参数)。
命令行工具的作者准备了若干条命令行用以测试你的程序。对于每个命令行,你的工具应当一直向后分析。当你的工具遇到某个字符串既不是合法的选项,又不是某个合法选项的参数时,分析就停止。命令行剩余的未分析部分不构成该命令的选项,因此你的程序应当忽略它们。
输入格式
输入的第一行是一个格式字符串,它至少包含一个字符,且长度不超过 52。格式字符串只包含小写字母和冒号,保证每个小写字母至多出现一次,不会有两个相邻的冒号,也不会以冒号开头。
输入的第二行是一个正整数 N(1 ≤ N ≤ 20),表示你需要处理的命令行的个数。
接下来有 N 行,每行是一个待处理的命令行,它包括不超过 256 个字符。该命令行一定是若干个由单个空格分隔的字符串构成,每个字符串里只包含小写字母,数字和减号。
输出格式
输出有 N 行。其中第 i 行以"Case i:" 开始,然后应当有恰好一个空格,然后应当按照字母升序输出该命令行中用到的所有选项的名称,对于带参数的选项,在输出它的名称之后还要输出它的参数。如果一个选项在命令行中出现了多次,只输出一次。如果一个带参数的选项在命令行中出 现了多次,只输出最后一次出现时所带的参数。
样例输入
albw:x
4
ls -a -l -a documents -b
ls
ls -w 10 -x -w 15
ls -a -b -c -d -e -l
样例输出
Case 1: -a -l
Case 2:
Case 3: -w 15 -x
Case 4: -a -b
问题分析
这道题实现不难,但是考虑全面拿满分太难了(CCF考试的时候又不会显示成绩,显然这道题就是个坑),我改了十多次才把90改到100分,考虑的点在代码中都有说明。
代码
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
using namespace std;
int main(){
const int format_len = 52;
const int order_len = 256;
int n,i,j,k;
bool wait_param;//用于判定当前是否正在等待接受参数
char format[format_len+1] = {'\0'},order[order_len+1] = {'\0'};
int option[26] = {0};//0-未出现的选项 1-无参数选项 2-有参数选项
bool option_existed[26];//记录每一命令行中出现的合法选项
int temp;
char params[26][order_len];
scanf("%s",format);
for(i=0;format[i]!='\0';i++){
if(format[i]!=':')
option[format[i]-'a'] = 1;
else
option[format[i-1]-'a'] = 2;
}
scanf("%d",&n);
getchar();
for(i=1;i<=n;i++){
memset(option_existed,false,sizeof(option_existed));
memset(params,'\0',sizeof(params));
wait_param = false;
gets(order);
printf("Case %d:",i);
for(j=0;order[j]!='\0'&&order[j]!=' ';j++);//跳过命令名
for(;order[j]!='\0';j++){
j++;
if(wait_param&&order[j]=='\0')//有参数选项参数为空(有空格隔开)
break;
if(!wait_param&&order[j]=='-'){
j++;
if(!(order[j]>='a'&&order[j]<='z'))
break;
temp = order[j] - 'a';
if(option[temp]==0)//不合法的选项名(合法是指在格式串要求内)
break;
else if(option[temp]==1){//合法无参数选项
if((order[j+1]==' '||order[j+1]=='\0'))//选项必须是单个字符
option_existed[temp] = true;
else
break;
}
else if(option[temp]==2){//合法有参数选项
if(order[j+1]==' ')//选项必须是单个字符
wait_param = true;
else
break;
}
}
else if(!wait_param&&order[j]!='-')
break;
else if(wait_param){
option_existed[temp] = true;
int index = 0;
for(;order[j]!='\0'&&order[j]!=' ';j++){
params[temp][index++] = order[j];
}
params[temp][index] = '\0';
wait_param = false;
j--;//使j回到'\0'或' '的前一位置,为了for循环的正确执行
}
}
for(j=0;j<26;j++){
if(option_existed[j]){
if(option[j]==1)
printf(" -%c",j+'a');
else if(option[j]==2){
printf(" -%c ",j+'a');
printf("%s",¶ms[j][0]);
}
}
}
printf("\n");
}
return 0;
}
测试样例
可以说这是题解的核心部分了,自己一个个测bug太折磨了······感觉给出了这些样例就基本上给出答案了。(只给出每一命令行语句,突出核心,Case部分不是难点,顺便提一句,在第一个选项错误时'Case x:'后边无空格也是可以的)
格式串:albw:x
输入:
①ls -w
②ls -w (结尾有空格)
③ls -a -w
④ls -w 23 -w
⑤ls -w 23 -w (结尾有空格)
⑥ls -al -a
⑦ls -wx 23
⑧ls -a -w xxx -a what
输出:
①Case _:
②Case _:
③Case _: -a
④Case _: -w 23
⑤Case _: -w 23
⑥Case _:
⑦Case _:
⑧Case _: -a -w xxx
就这样吧。