CSP-201403-3-命令行选项
关键点:将整行字符串按空格分割
在解析命令行时,一个常见的需求是将整个命令行字符串分割成多个部分,通常以空格为分隔符。这些部分包括命令行工具的名称、选项(可能带有前缀
-
或--
)和这些选项的参数。C++中,std::stringstream
类是处理这种任务的一个非常方便的工具,因为它允许我们像处理输入文件一样处理字符串,使用空白字符(如空格)作为默认的分隔符。下面的代码段展示了如何使用stringstream
来分割命令行:
string cmdLine;
getline(cin, cmdLine); // 从标准输入读取整行命令行
stringstream ss(cmdLine); // 将命令行字符串封装进 stringstream
vector<string> tokens; // 用于存储分割后的字符串
string token; // 临时变量,用于存储每次从 stringstream 中提取的字符串// 使用 while 循环和 >> 操作符从 stringstream 中提取字符串
// 操作符 >> 会自动根据空白字符(包括空格、制表符等)分割字符串
while (ss >> token) {tokens.push_back(token); // 将提取的字符串存入 vector
}
解题思路
-
初始化和读取输入:
- 程序首先读入一个格式字符串
formatStr
,该字符串定义了命令行工具接受的选项及其类型(带参数或不带参数)。 - 然后,读取一个正整数
n
,表示需要处理的命令行个数。 - 为每种选项设置两个布尔数组
hasNoArg
和hasArg
,分别用于标记无参数选项和带参数选项。
- 程序首先读入一个格式字符串
-
预处理选项类型:
- 使用一个循环遍历格式字符串
formatStr
。 - 如果一个字母后面跟着一个冒号,则表示这是一个带参数的选项,将对应的
hasArg
设置为true
,并跳过冒号。 - 如果字母后面没有冒号,则表示这是一个不带参数的选项,将对应的
hasNoArg
设置为true
。
- 使用一个循环遍历格式字符串
-
命令行处理:
- 使用
stringstream
将整个命令行分割为单独的字符串(tokens),这些字符串包括命令行工具的名字和后面的选项或参数。 - 清空存储选项参数的数组
optionArgs
,为新的命令行准备。
- 使用
-
解析命令行选项:
- 遍历命令行中的每个字符串(从第二个开始,因为第一个是命令行工具的名字)。
- 检查每个字符串是否符合无参数选项的格式(以"-"开头,后跟单个小写字母)。
- 如果是无参数选项,并且这个选项在格式字符串中定义了,则在
optionArgs
中为该选项设置一个特殊值(如"#")来表示该选项存在但无参数。 - 如果是带参数选项,并且这个选项在格式字符串中定义了,且后面紧跟着一个参数,则将这个参数保存到
optionArgs
中,并跳过这个参数,以免将其误认为另一个选项。
-
输出结果:
- 遍历
optionArgs
数组,按字母顺序输出所有在命令行中出现的选项。 - 对于无参数选项,只打印选项名。
- 对于带参数选项,打印选项名和最后出现时所带的参数。
- 如果一个选项在命令行中未出现,或者格式不正确,则忽略它。
- 遍历
完整代码
#include<iostream>
#include<string>
#include<vector>
#include<sstream>
using namespace std;// 定义常量,代表可能的最大选项数
const int MAX_OPTIONS = 26;// 定记无参选项和有参选项
bool hasNoArg[MAX_OPTIONS];
bool hasArg[MAX_OPTIONS];// 存储每个选项的参数(如果有)
string optionArgs[MAX_OPTIONS];int main()
{string formatStr;cin >> formatStr;// 预处理选项类型for (int i = 0; i < formatStr.length(); i++) {if (i + 1 < formatStr.length() && formatStr[i + 1] == ':') {hasArg[formatStr[i] - 'a'] = true;i++; // 跳过冒号}else {hasNoArg[formatStr[i] - 'a'] = true;}}int n;cin >> n;cin.ignore(); // 吸收换行符for (int i = 1; i <= n; i++) {string cmdLine;getline(cin, cmdLine);cout << "Case " << i << ":";stringstream ss(cmdLine);vector<string> tokens;string token;// 分割命令行至vector中while (ss >> token) {tokens.push_back(token);}// 清空每个选项的参数,为新的命令行准备for (int j = 0; j < MAX_OPTIONS; j++) {optionArgs[j].clear();}// 解析命令行for (int j = 1; j < tokens.size(); j++) {if (tokens[j][0] != '-' || tokens[j].length() != 2 || tokens[j][1] < 'a') break;int index = tokens[j][1] - 'a';if (hasNoArg[index]) {optionArgs[index] = "#"; // 代表该选项存在,但没有参数}else if (hasArg[index] && j + 1 < tokens.size()) {optionArgs[index] = tokens[++j]; // 存储选项参数并跳过参数}else break;}// 输出选项和参数for (int j = 0; j < MAX_OPTIONS; j++) {if (!optionArgs[j].empty()) {cout << " -" << char(j + 'a');if (hasArg[j]) cout << " " << optionArgs[j];}}cout << endl;}return 0;
}
文章部分内容参考自:【ccf-csp题解】第1次csp认证-第三题-命令行选项-字符串模拟