最近好像开始炒冷饭了0.0(因为自己太菜了洛谷写不明白
一·题面
【问题描述】
编写一程序检查C源程序文件中{}、()等括号是否匹配,并输出第一个检测到的不匹配的括号及所对应括号所在的行号(程序中只有一个括号不匹配)。
注意:
1.除了括号可能不匹配外,输入的C源程序无其它语法错误。
2.字符常量、字符串常量及注释中括号不应被处理,注释包括单行注释//和多行/* */注释
3.字符常量和字符串常量中不包含转义字符\'和\";
4.程序中出现有意义括号的个数不超过200个;
不匹配判断规则:
1.当检测的程序括号为'{'时,若其前序尚未匹配的括号为'('时,输出该'('左括号及所在行号;
2.当遇到一个不匹配的右括号')'或'}'时,输出该右括号及所在行号;
3.当程序处理完毕时,还存在不匹配的左括号时,输出该左括号及所在行号。
【输入形式】
打开当前目录下文件example.c,查询其括号是否匹配。该文件中每行字符数不超过200。
【输出形式】
若存在括号不匹配时,应输出首先能判断出现不匹配的括号及其所在的行号。当出现括号不匹配时,按下面要求输出相关信息:
without maching at line
其中为‘{’, ‘}’, ‘(’, ‘)’等符号,为该符号所在的行号。
若整个程序括号匹配,则按下面所示顺序输出括号匹配情况,中间没有空格。
(){(()){}}
【样例输入1】
若当前目录下输入文件example.c中内容如下:
#include
int main(){
printf("{ hello world }\n"); // }
)
【样例输出1】
without maching ')' at line 4
【样例输入2】
若当前目录下输入文件example.c中内容如下:
#include
int main(){
printf("{ hello world }d\n"); /* }*/
【样例输出2】
without maching '{' at line 2
【样例输入3】
若当前目录下输入文件example.c中内容如下:
#include
int main(){
printf("{ hello world }d\n"); /* }*/
}
【样例输出3】
(){()}
【样例说明】
样例1:在注释部分和字符串中的括号不考虑,在将程序处理之后得到的括号序列是(){()),遇到右括号时与最近的左括号匹配,发现最后一个小括号和大括号不匹配。
样例2:处理之后的括号序列是(){(),在最后缺少了右大括号,那么应该输出与之相对应的左括号不匹配。
【评分标准】
通过所有测试点得满分。
题意分析:
括号匹配本身是个很简单的问题,使用栈就可以解决,但是这个题目的难点不在于此:
本题把括号匹配这个经典的栈问题放到了一个代码的情景之中,出现了单行注释,多行注释,引号等多种干扰,本题的难点就在于排除这些干扰项
二·干扰处理
由题,文章有四种干扰:
单行注释// 多行注释/*...*/ 单引号'c' 双引号"..."
我们可以发现,除了多行注释都发生在一行之中,所以采取的策略是:先读入一行,处理完三种情况以后,存入到一个二维数组中,最后再处理多行注释。
1·单行处理
对于单行的处理,第一次接触这个题的时候我想到的是strstr函数,但是这样有一个弊端:三种干扰可能交杂出现,而其优先级应该是和其出现位置有关的(也就是说我们要优先考虑最先出现的干扰项),而用strstr函数的时候,优先级和你调用三个strstr函数的顺序有关。这样说可能亿点点抽象,不如看一个例子:
对于"xx//x",这个//实在双引号内部的,不应该被识别到,但是如果strstr(line,"//")在strstr(line,"\"")之前调用,就会错误识别到这个//
所以从左到右遍历字符串,同时检查有没有出现三种更舒服:
void process_line(char *line){
for(int i=0;i<strlen(line)-1;i++){
if(line[i]=='/'&&line[i+1]=='/'){
for(;i<strlen(line);i++) line[i]='0';
break;
}
else if(line[i]=='\''&&line[i+2]=='\''){
line[i]=line[i+1]=line[i+2]='0';
i=i+2;
continue;
}
else if(line[i]=='\"'){
line[i++]='0';
while(line[i]!='\"') line[i++]='0';
line[i]='0';
continue;
}
}
}
2·多行处理
多行处理就没什么技巧性了,用一个flag记录一下即可
void process_all(){
int flag = 0;
for(int i=0;i<lcnt;i++){
if(flag){
char *q = strstr(art[i],"*/");
if(q!=NULL){
flag = 0;
for(char *p=art[i];p<=q+1;p++) *p='0';
}
}
char *p=strstr(art[i],"/*");
if(p!=NULL){
char *q = strstr(art[i],"*/");
if(q!=NULL){
for(;p<=q+1;p++) *p='0';
}
else{
for(;*p!='\0';p++) *p='0';
flag = 1;
}
}
}
}
三·括号匹配
括号匹配对四种括号分别讨论即可,注意,由于要输出错误括号的行数,所以要用一个结构体在记录括号的同时也记录行数。(同时,对于行数,在读入的时候也要小心。样例两行之间是有一个空行的,要跳过空行,否则会导致行数比预期的大)
void brackets_match(){
brk stack[100];
int top = -1;
for(int i=0;i<lcnt;i++){
for(int j=0;j<strlen(art[i]);j++){
if(art[i][j]=='{'){
if(top>=0&&stack[top].c=='('){
printf("without maching '(' at line %d",stack[top].lnum);
return ;
}
top++;
stack[top].c='{';
stack[top].lnum=i+1;
}
if(art[i][j]==')'){
if(top>=0&&stack[top].c=='(') top--;
else{
printf("without maching ')' at line %d",i+1);
return ;
}
}
if(art[i][j]=='}'){
if(top>=0&&stack[top].c=='{') top--;
else{
printf("without maching '}' at line %d",i+1);
return ;
}
}
if(art[i][j]=='('){
top++;
stack[top].c='(';
stack[top].lnum=i+1;
}
}
}
if(top>=0&&(stack[top].c=='{'||stack[top].c=='(')){
printf("without maching '%c' at line %d",stack[top].c,stack[top].lnum);
return ;
}
puts("well brackets");
}
全部代码如下:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXLINE 210
#define MAXSIZE 1000
/*
先对一行进行处理 存储全部以后再对多行注释处理
*/
char art[MAXSIZE][MAXLINE]={{'\0'}};
int lcnt=0;
void process_line(char *line){
for(int i=0;i<strlen(line)-1;i++){
if(line[i]=='/'&&line[i+1]=='/'){
for(;i<strlen(line);i++) line[i]='0';
break;
}
else if(line[i]=='\''&&line[i+2]=='\''){
line[i]=line[i+1]=line[i+2]='0';
i=i+2;
continue;
}
else if(line[i]=='\"'){
line[i++]='0';
while(line[i]!='\"') line[i++]='0';
line[i]='0';
continue;
}
}
}
void process_all(){
int flag = 0;
for(int i=0;i<lcnt;i++){
if(flag){
char *q = strstr(art[i],"*/");
if(q!=NULL){
flag = 0;
for(char *p=art[i];p<=q+1;p++) *p='0';
}
}
char *p=strstr(art[i],"/*");
if(p!=NULL){
char *q = strstr(art[i],"*/");
if(q!=NULL){
for(;p<=q+1;p++) *p='0';
}
else{
for(;*p!='\0';p++) *p='0';
flag = 1;
}
}
}
}
typedef struct braket_type{
char c;
int lnum;
}brk;
void brackets_match(){
brk stack[100];
int top = -1;
for(int i=0;i<lcnt;i++){
for(int j=0;j<strlen(art[i]);j++){
if(art[i][j]=='{'){
if(top>=0&&stack[top].c=='('){
printf("without maching '(' at line %d",stack[top].lnum);
return ;
}
top++;
stack[top].c='{';
stack[top].lnum=i+1;
}
if(art[i][j]==')'){
if(top>=0&&stack[top].c=='(') top--;
else{
printf("without maching ')' at line %d",i+1);
return ;
}
}
if(art[i][j]=='}'){
if(top>=0&&stack[top].c=='{') top--;
else{
printf("without maching '}' at line %d",i+1);
return ;
}
}
if(art[i][j]=='('){
top++;
stack[top].c='(';
stack[top].lnum=i+1;
}
}
}
if(top>=0&&(stack[top].c=='{'||stack[top].c=='(')){
printf("without maching '%c' at line %d",stack[top].c,stack[top].lnum);
return ;
}
puts("well brackets");
}
int main(){
char line[MAXLINE];
FILE *src = fopen("example.c","r");
while(fgets(line,210,src)){
if(line[0]=='\n') continue;//跳过空行
process_line(line);
//puts(line);
strcpy(art[lcnt++],line);
}
process_all();
//for(int i=0;i<lcnt;i++) printf("%d ",i+1),puts(art[i]);
brackets_match();
}