链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
vigoss18在某997工作制的公司上班,终于有一天爆发了,决定要跑路。
既然要跑路了,当然得对自己的代码做点手脚,既要保证走了之后代码仍然可以运行,又要保证走了之后别人维护不了,所以决定写个程序,用来批量把代码中的注释全部删掉。
vigoss18是一个强烈的强迫症患者,他的代码都符合下面这些规则:
1.所有的注释都是/**/风格的,两个星号中间的内容为注释内容,需要把这个符号和里面的内容全部去掉
2.代码中经常会出现引号,用来表示字符串,如果/**/出现在引号内部,那么就认为不是注释,是不能被去掉的
3.vigoss18的代码保证不会出现/**/镶套,但是可能会出现/*/**/和/**/*/这种情况,对于前者,有两个/*,第一个先匹配,第二个/*被认为是注释内部的内容;对于后者,第一个*/被匹配,第二个*/找不到左边匹配的,所以被认为是文本,需要保留下来。
4.代码中可能会出现一半注释符号,比如单独的/*,或者单独的*/,这个时候认为不是注释,需要保留下来.
5.注释外的引号,保证一定是合法的,即每个引号一定是有对应的另一个引号成对匹配的。
6.代码中可能会出现引号前面有反斜杠的情况,那么这时引号会被转义,只被认为是个单纯的符号,不起到匹配字符串的效果。
7.代码保证只有引号才有转义的情况发生,即除了引号,其他符号都不需要考虑前面有反斜杠然后被转义。
做题细节:
1、咋么读入换行?
一开始想到'\0'和EOF两个截止符,但前者效果不好,后来上网查了查两个的区别,EOF用于文件读取,而'\0'只用于字符串结尾,所以正确读取方式为scanf+EOF。另外,这种方法还可以帮助我们得知字符串长度n:
while(scanf("%c",&s[++n])!=EOF);
2、如何简化代码?
我们可以在内层循环里,通过讨论不同情况为i加速。比如想要判断 /* ,就必须满足s[i]=='/'&&s[i+1]=='*',所以在这种判断下加速了i+1的进程,直接在循环体内部让i++即可。
3、关于思考不周的问题(调了我一个点QAQ……)
/**/部分没考虑周到。一开始是用队列存储,判断条件是s[i]=='*'&&s[i-1]=='/'就视为匹配情况退出循环,此时漏掉了一种毒瘤情况:/*/。所以说审题的重要性啊,题目中其实已经给过这种情况了。
4、“探查兵”法
后来发现用队列其实是多余的,可以通过设置i在输出字符前先探探路,若符合则使j从一开始的位置往后输出,像是先派出了探查兵。分析可以发现,这种方法可以使用于这种前后有标志性开始结束标志的处理要求的题,较之前的内层循环有不易错判循环状态的好处。
总结完毕,上代码:
#include<bits/stdc++.h>
#include<stdio.h>
using namespace std;
#define N 100000
char str[N];
int main() {
int a=0,k=0,n,f=0;
while(scanf("%c",&str[++n])!=EOF);
// str[n]='&';
n--;
for(int i=1; i<=n; i++) {
if(str[i]=='"'&&str[i-1]!='\\') {
cout<<str[i];
i++;
while(1) {
cout<<str[i];
if(i>n||str[i]=='"'&&str[i-1]!='\\')break;
i++;
}
} else if(str[i]=='/'&&str[i+1]=='*') {
int j=i;
i+=3;
while(1) {
if(i>n||(str[i]=='/'&&str[i-1]=='*'))break;
i++;
}
//cout<<i<<endl;
if(i>n) while(j<=n) cout<<str[j++];
} else cout<<str[i];
}
}