1. 程式人生 > >201403-3命令列選項(c++,字串處理)

201403-3命令列選項(c++,字串處理)

試題編號: 201403-3
試題名稱: 命令列選項
時間限制: 1.0s
記憶體限制: 256.0MB
問題描述:

問題描述

  請你寫一個命令列分析程式,用以分析給定的命令列裡包含哪些選項。每個命令列由若干個字串組成,它們之間恰好由一個空格分隔。這些字串中的第一個為該命令列工具的名字,由小寫字母組成,你的程式不用對它進行處理。在工具名字之後可能會包含若干選項,然後可能會包含一 些不是選項的引數。
  選項有兩類:帶引數的選項和不帶引數的選項。一個合法的無引數選項的形式是一個減號後面跟單個小寫字母,如"-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

 

        本題大意是給定一個格式,再給幾個命令列,命令列中包括選項或引數,要求輸出命令列中符合格式條件的選項或引數。

        本題難點在於命令列中的選項或引數是由空格分隔開的,處理輸入和將選項或引數取出時比較麻煩。輸入的問題可以用c++中的getline函式來解決,getline作用是接收一行資料;需要注意的是,程式開始時輸入了一個字串和一個數字,getline函式會將輸入數字時的換行符接收上,導致接收的第一行命令列為空,所以要在輸入數字的語句後加getchar(),用於接收換行符。取出選項和引數的問題可以用strtok函式來解決,這個函式類似於java中的split函式,用於分割字串。

        若選項帶引數,需要輸出最後一個引數。這個問題用一個map來解決,map的key為選項,value儲存最後一次出現的引數。程式碼如下:

#include<iostream>
#include<string.h>
#include<map>
using namespace std;
string format;    //格式字串
char word[256];    //輸入的命令列
int n;
int main()
{
	cin>>format>>n;
	getchar();    //接收上一句的換行符
	for(int i=0;i<n;i++)
	{
		map<string,string> m;
		bool flag=false;
		cin.getline(word,256);
		char *cmd=strtok(word," ");    //此時取出的是命令列的名字,應該忽略。
		cmd=strtok(NULL," ");    //此後strtok的引數都應該是NULL,此時取出的是第一個選項
		char *temp=NULL;
		while(cmd)
		{
                        //若取出的字串是一個選項,即一個減號加一個字母
			if(strlen(cmd)==2 && cmd[0]=='-')
			{
                                //查詢這個選項在不在格式中
				int pos=format.find(cmd[1]);
				if(pos==-1)
					break;
                                //若map中還沒有出現過這個選項,則新增進去
				if(m.find(cmd)==m.end())
					m[cmd]=="";
                                //temp取出當前選項後面的字串
				temp=strtok(NULL," ");
                                //判斷當前選項帶不帶參,如果帶引數就把temp儲存到map中。
				if(format[pos+1]==':' && temp)
				{
					m[cmd]=temp;
					flag=true;
				}
			}
                        //若當前遇到了不是選項的字串就退出,當前命令列剩餘的字串全部忽略。
			else
				break;

                        //現在的temp為當前選項的後一個字串
                        //若當前的字串是個帶參的選項,那麼就跳到temp的後面的那個字串上
			if(flag)
			{
				cmd=strtok(NULL," ");
				flag=false;
			}
                        //若當前選項不帶參,就把temp作為下一個選項來處理。
			else
				cmd=temp;
		}
		cout<<"Case "<<i+1<<":";
		for(map<string,string>::iterator it=m.begin();it!=m.end();it++)
		{
			cout<<" "<<it->first;
			if(it->second!="")
				cout<<" "<<it->second;
		}
		cout<<endl;
	}
	return 0;
}