oo-pre第六次作业总结
题面
(这里只强调改动)
- qsend和qrecv的模糊查询模式新增四个参数-ssq, -ssr, -pre, -pos,从左到右分别表示:查询以后续输入字符串为子序列(subsquence),子串(substring),前缀(prefix),后缀(postfix)的发送者/接收者名称的消息。即现在上述两条指令的完整形式为qsend [-v] [param] “str”和qrecv [-v] [param] “str”。其中param为上述四个参数中的一个。当param缺省而-v存在时,表示含义与param=-ssr且-v存在时一致。
- 所有指令新增参数-c “str”(-c: clean)表示将所有该指令输出消息中的消息内容中的子串str(引号是指令格式要求,并非str内的内容)改为由字符’ * ‘组成的字符串后再输出,其长度与被修改的字符串长度相同。该参数永远是所有指令的最后一个参数。且子串匹配优先级为从左到右(具体解释见样例)
指令参数之间的顺序关系见后续限制说明部分以及样例。
这里我们还需要大家实现对指令格式的检查。格式错误的指令只需按照指导书要求输出即可,无需将错误指令执行,具体如下:
- qdate指令的日期若不符合现实中的日期表示,则需要输出Command Error!: Wrong Date Format! “cmd”,其中cmd为出错指令。
- qsend和qrecv中,新增的四个参数只适用于模糊匹配,所以,若-ssq, -ssr, -pre, -pos参数在-v参数之前出现,或-v参数未出现而这四个参数出现了,则需要输出Command Error!: Not Vague Query! “cmd”,其中cmd为出错指令。
- 显然一条指令至多只有一种错误。
输入样例:
1 |
|
输出样例:
1 |
|
样例解释:
对于最后一条指令,忽略-c参数时的输出如下:
1 |
|
- 考虑-c第一条消息的内容不以aa为子串,而第二条消息的内容中存在子串aa,根据从左往右的匹配规则,将前两个aa替换成* *后输出。
- 若第二条消息的原版是1999/12/31-earthwarrior@militaryleader:”aaaah! I forget it.”;,则根据从左到右的匹配规则,会先匹配到前两个aa并将其替换成* ,然后匹配到后两个aa并替换成 ,最终输出的是1999/12/31-earthwarrior@militaryleader:” * * *h! I forget it.”;(星号中间没有空格)
限制说明(在上一次的基础上):
- 保证所有的消息符合格式,指令错误只涉及上面谈到的那些类型。
- qdate指令保证输入的日期中年月日三个参数不同时缺省。
- qsend和qrecv指令中,保证-ssq, -ssr, -pre, -pos四个参数至多出现其中一个。
- 正文内容仅由大小写英文字母、数字、空格、四种标点符号(? ! , .)构成。
- 日期格式异常只需考虑月,日大小以及平闰年,无需考虑1582年的10月份少了10天等类似的非常偏门的错误。
- 当日期发生参数缺省时,只需考虑已给定参数的合法性,具体而言。若在固定已有参数值的情况下,存在缺省参数的一组取值,使得日期合法,则认为该日期参数合法。
例子1:指令qdate /2/29合法,因为2月可以有29日,且当年份为闰年时,整个日期合法,所以 该日期参数合法。
例子2:指令qdate /9/31非法,因为9月不可能有31日,这与缺省的年份无关。
例子3:指令qdate 2022//31合法,因为存在有31号的月份。
例子4:指令qdate //32非法,因为不存在有32号的月份。这与缺省的年、月份无关。
例子5:指令qdate /13/非法,因为不存在有13月的年份,这与缺省的年、日无关。
例子6:指令qdate //0非法,因为不存在0号。
题解
(同样只重点提一下和上次的差别)
由于和之前的状态相比,对于输入的要求字符串要匹配的项目变多,如果全部放在main中会让main函数比较冗长,因此新建了一个operate类对这些要求进行分类读取。
main函数中:1
2
3
4
5Operate operate = new Operate();
while (scanner.hasNext()) {
String inputQuest = scanner.nextLine();
operate.operation(inputQuest, memory);
}对operate类,要进行两到三个东西的检查:如果是针对发送者和接收者,则要检查-v,param和-c的检查。
注意几个事情:首先是对-c进行检查,如果没有-c就直接判断-v(因为本体param和-v是完全相关的,一个正确的模糊输入必须要有-v,所以只需要整个输入就不会漏掉信息),其次是如果有-c的情况,要单独分离-c后面的屏蔽词,所以不能直接split”-“符号(可能把-v也split了),我的方法是把它用另一个符号”#“替换再分开即可。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18if (quest.substring(0, 5).equals("qsend")) { //查询输入相同发送者
if (!quest.contains("-c")) { //不需要屏蔽词
if (quest.substring(6, 8).equals("-v")) { //模糊输入
memory.printSenderV(quest.substring(6), quest, "");
} else {
memory.printSender(quest.substring(6), quest, "");
}
} else {
String newQuest = quest.replace("-c", "#c");
String[] clearString = newQuest.split("#");
String[] needClear = clearString[1].split("\"");
if (quest.substring(6, 8).equals("-v")) { //模糊输入
memory.printSenderV(clearString[0].trim().substring(6), quest, needClear[1]);
} else {
memory.printSender(clearString[0].trim().substring(6), quest, needClear[1]);
}
}
}而如果是针对时间则只需要考虑-c的情况,同样需要分离需要被替换的词(先用-分再用“分,最后取出)。
1
2
3
4
5
6
7
8
9if (quest.substring(0, 5).equals("qdate")) { //查询输入相同日期
if (!quest.contains("-c")) { //不需要屏蔽词
memory.printDate(quest.substring(6), quest, "");
} else { //需要屏蔽词,格式为qdate yyyy/mm/dd -c "Str"
String[] clearString = quest.split("-");
String[] needClear = clearString[1].split("\"");
memory.printDate(clearString[0].trim().substring(6), quest, needClear[1]);
} //qdate 12/23 -c "f"
}
3.对于时间的输入,首先判断是否错误。我在这里写了一个判断错误的函数:
1 |
|
其精髓就是要考虑最好情况,就比如在年份缺省的时候,就默认其为闰年,默认2月可以有29天;如果月份缺省,就默认每个月最多都可以有31号。
然后首先进行错误分析,进行错误抛出:
1 |
|
对正确情况,就进行屏蔽操作。我对printDate,printSender等等多加了一个字符串的输入,代表的是应该被屏蔽的字符串。当其为空时则不用屏蔽,如果非空就进行屏蔽操作:
1 |
|
对于屏蔽操作,我也进行了一个函数的封装,用来对原有字符串改变为星号。其原理就是,首先看屏蔽词的长度,然后生成同样长度的星号串,最后利用replace函数将内容改变。
这里有一个重点:屏蔽词只屏蔽内容!比如屏蔽字符”1“就只能屏蔽内容的1而不能屏蔽日期中的。所以要把原有字符串引号中的内容提取出来再进行更换,最后字符串拼接后输出。
1 |
|
- 考虑发送、接收者相关函数:
如果没有-v时,判断错误只需要判断有没有多余的-param就可以,此时同样写了一个函数:这样判断完这个函数就可以直接利用上面的方法进行输出,不再赘述。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public boolean checkPeople(String quest) {
if (quest.contains("-ssq")) {
return false;
}
if (quest.contains("-ssr")) {
return false;
}
if (quest.contains("-pre")) {
return false;
}
if (quest.contains("-pos")) {
return false;
}
return true;
}
如果有-v时,也需要判断错误,但是这个时候判断的错误是-param是否在-v前面,这个函数需要改成:
1 |
|
意思就是如果有param就要有后置的一个-v,非常易于理解。随后就是针对不同的四种param进行输出处理。
对于-ssq:此处检测的是子序列,没有现成的函数,需要自己写一个函数进行判断,这里是-ssq的输出函数:(同样最后考虑了是否需要屏蔽,同样套用上面的方法)
1 |
|
子序列检测函数:(子序列相当于可以断开的子串)就是对子串的每一个字符都从检测字符串从前往后检测,如果检测到了就从该位开始检测下一个字符,最后如果所有字串字符都能按顺序在检测字符串中找到,则证明子串是子序列。函数如图:
1 |
|
对于-pre(前缀检测):直接利用现有的前缀检测函数startsWith即可。如下:
1 |
|
对于-pos(后缀检测)也类似,只是利用的是后缀检测函数endsWith。
对于-ssr,就和只有-v是等价的,只需要进行屏蔽操作就可以了,不再赘述。
以上,就是第六次作业的改动总结。又一个场景结束啦,最后一次看上去好难的样子orz