CCF CSP 201403-3.命令行选项

问题描述

  请你写一个命令行分析程序,用以分析给定的命令行里包含哪些选项。每个命令行由若干个字符串组成,它们之间恰好由一个空格分隔。这些字符串中的第一个为该命令行工具的名字,由小写字母组成,你的程序不用对它进行处理。在工具名字之后可能会包含若干选项,然后可能会包含一 些不是选项的参数。
  选项有两类:带参数的选项和不带参数的选项。一个合法的无参数选项的形式是一个减号后面跟单个小写字母,如”-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


分析:

定义长度为123的一维数组type(z的ASCII值为122),用于表示命令行选项的类型。

当值为0时,表示选项不属于该命令;当值为1时,表示带参数的选项;当值为2时,表示不带参数的选项。

题目要求按照字母升序输出命令行中用到的所有选项,因此可以使用C++中的map(Java中的TreeMap)存储选项及参数。

处理输入的命令行时,直接跳过命令名,只处理后面的选项。

若当前选项不合法(不是一个减号后面跟单个小写字母),或者不属于该命令,则分析停止;

若为带参数的选项,且存在参数,则将其存储在map中;

若为不带参数的选项,则为其参数赋空字符串""

C++中,可以使用stringstream处理命令行中的空格;Java中,直接使用String类的split方法,按照空格分割字符串。

  • C++版
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
#include <map>
#include <string>
#include <sstream>
using namespace std;

int main() {
string args, cmd;
int n;
// 吸收换行符
char c;
cin >> args >> n >> c;

// 处理给定的命令行选项,0表示不属于该命令,1表示带参数的选项,2表示不带参数的选项
int type[123] = { 0 };
for (int i = 0; i < args.size(); i++) {
if (i <= args.size() - 2 && args[i + 1] == ':') {
type[args[i++]] = 1;
} else {
type[args[i]] = 2;
}
}

for (int i = 0; i < n; i++) {
map<char, string> dict;
stringstream ss;

getline(cin, cmd);
ss << cmd;
// 跳过命令名
ss >> cmd;
while (ss >> cmd) {
// 若当前选项不合法,或者不属于该命令,分析停止
if (!(cmd.size() == 2 && cmd[0] == '-') || type[cmd[1]] == 0) {
break;
}
// 若为带参数选项
if (type[cmd[1]] == 1) {
// 若存在参数,则存储到map中;否则,循环结束
if (ss >> args) {
dict[cmd[1]] = args;
}
} else {
// 不带参数的选项,赋空字符串
dict[cmd[1]] = "";
}
}

cout << "Case " << i + 1 << ":";
for (map<char, string>::iterator iter = dict.begin();
iter != dict.end(); iter++) {
cout << " -" << iter->first;
if (!iter->second.empty()) {
cout << " " << iter->second;
}
}
cout << endl;
}
return 0;
}
  • Java版
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;

public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String arguments = scan.nextLine();
int n = Integer.parseInt(scan.nextLine());

// 处理给定的命令行选项,0表示不属于该命令,1表示带参数的选项,2表示不带参数的选项
int[] type = new int[123];
for (int i = 0; i < arguments.length(); i++) {
if (i <= arguments.length() - 2 && arguments.charAt(i + 1) == ':') {
type[arguments.charAt(i++)] = 1;
} else {
type[arguments.charAt(i)] = 2;
}
}

StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
Map<Character, String> map = new TreeMap<>();
String[] sArr = scan.nextLine().split(" ");
for (int j = 1; j < sArr.length; j++) {
char[] cmd = sArr[j].toCharArray();
// 若当前选项不合法,或者不属于该命令,分析停止
if (!(cmd.length == 2 && cmd[0] == '-') || type[cmd[1]] == 0) {
break;
}
// 若为带参数选项
if (type[cmd[1]] == 1) {
// 若存在参数,则存储到map中;否则,循环结束
if (j < sArr.length - 1) {
map.put(cmd[1], sArr[++j]);
}
} else {
// 不带参数的选项,赋空字符串
map.put(cmd[1], "");
}
}

sb.append("Case ").append(i + 1).append(':');
map.forEach((k, v) -> {
sb.append(" -").append(k);
if (!v.isEmpty()) {
sb.append(' ').append(v);
}
});
sb.append("\n");
}
scan.close();

System.out.println(sb.toString());
}
}

----------本文结束感谢您的阅读----------
坚持原创技术分享,您的支持将鼓励我继续创作!