实验要求
设计一个程序,从任意字符串中剔除C语言形式的注释,包括:
①形如: //… 的单行注释;
②形如: /…/ 的多行注释。
(1)输入文件:input.txt,纯文本。内容是一个可能带有注释的源程序字符串。
(2)输出文件:output.txt。内容是剔除可能存在的注释之后剩余的字符串。
编程环境和语言
编程语言:C++
IDE:vs 2019
实验原理分析
按行读取,有两个字符变量,用来存储当前字符和上一个字符,若两个字符为“//”或者“/*”,则说明进入到注释部分,后面的数据都可以忽略,同时将空白字符忽略掉。另外还需要注意一种特殊的情况,即在引号对中的注释符号应该不能够被理解为注释。
程序关键部分分析
进行预处理的函数为pre_process(ifstream& fin, ofstream& fout)
定义
在pre_process()函数中,主要定义的变量如下所示:
char buff[1024] = { '\0' }; //用来存储读入的数据
char data[1024] = { '\0' }; //用来存储处理过的数据
char old_c = '\0'; //用来存储上一个字符
char cur_c; //用来存储当前字符
int in_comment = 0; //0表示当前字符未在注释里,1表示在多行注释中,2表示在单行注释中,3表示在双引号中,4表示在单引号中
bool first = true; //判断是否读入的是第一行,以决定是否在输出文件前先输出换行符
int i = 0; //计数器,记录buff
int j = 0; //计数器,记录data
关键部分分析
关键部分的代码如下所示:
while (fin.getline(buff, sizeof(buff))) {
while (i < strlen(buff)) {
cur_c = buff[i++]; //首先将获取的字符存入缓存中
switch (in_comment) {
case 0:
if (cur_c == '\"') { //进入双引号中
data[j++] = cur_c;
in_comment = 3;
}
else if (cur_c == '\'') { //进入单引号中
data[j++] = cur_c;
in_comment = 4;
}
else if (old_c == '/' && cur_c == '*') { //进入多行注释中
j--;
in_comment = 1;
}
else if (old_c == '/' && cur_c == '/') { //进入单行注释中
j--;
in_comment = 2;
}
else if (isspace(cur_c)) {
//若为空白字符,则不存入data中
}
else { //其他情况则直接将数据写入data中
data[j++] = cur_c;
}
break;
case 1:if (old_c == '*' && cur_c == '/') in_comment = 0; //多行注释结束
break;
case 2:if (i == strlen(buff)) in_comment = 0; //单行注释到这行结束时标志位置为0
break;
case 3:
data[j++] = cur_c;
if (cur_c == '\"') in_comment = 0;
break;
case 4:
data[j++] = cur_c;
if (cur_c == '\'') in_comment = 0;
break;
}
old_c = cur_c; //保留上一个字符
}
if (j > 0) { //若这一行处理过后的data数组有数据,则读出到文件中
if (!first) {
fout << '\n';
}
else first = false;
for (int k = 0; k < j; k++) {
fout << data[k];
}
}
i = j = 0; //读取新的一行数据前,这些变量先进行重置
}
if (in_comment != 0) fout << '\n' << "error"; //若标志位不等于0,则说明多行注释不到位,没有结束标志
这里需要注意的是,形如:
"sdf//sdf"
'sdf//sdf'
这种输入,即引号中的双斜杠不应该被理解为注释符!!!
主程序
int main() {
ifstream fin("input.txt");
while (!fin.is_open()) {
cout << "文件不存在!";
return 0;
}
ofstream fout("output.txt");
pre_process(fin, fout);
fin.close(); fout.close();
return 0;
}
程序测试
测试用例1的输入为:
start
abc/*def
ghi*/
lmn//opq
rst/uvw
x*y*/z
end
输出的结果为:
start
abc
lmn
rst/uvw
x*y*/z
end
测试用例2的输入为:
start
123
7
abc/d
ef
jk
t
end
输出的结果为:
start
123
7
abc/d
ef
jk
t
end
测试用例3的输入为:
start
123//456
7//8/*9//
abc/d
ef/*ghi*/
jk/*
end
输出的结果为:
start
123
7
abc/d
ef
jk
error
测试用例4的输入为:
start
pri"sdf//sdf"//sdf
end
输出结果为:
start
pri"sdf//sdf"
end
完整代码
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
void pre_process(ifstream& fin, ofstream& fout) {
char buff[1024] = { '\0' }; //用来存储读入的数据
char data[1024] = { '\0' }; //用来存储处理过的数据
char old_c = '\0'; //用来存储上一个字符
char cur_c; //用来存储当前字符
int in_comment = 0; //0表示当前字符未在注释里,1表示在多行注释中,2表示在单行注释中,3表示在双引号中,4表示在单引号中
bool first = true; //判断是否读入的是第一行,以决定是否在输出文件前先输出换行符
int i = 0; //计数器,记录buff
int j = 0; //计数器,记录data
while (fin.getline(buff, sizeof(buff))) {
while (i < strlen(buff)) {
cur_c = buff[i++]; //首先将获取的字符存入缓存中
switch (in_comment) {
case 0:
if (cur_c == '\"') { //进入双引号中
data[j++] = cur_c;
in_comment = 3;
}
else if (cur_c == '\'') { //进入单引号中
data[j++] = cur_c;
in_comment = 4;
}
else if (old_c == '/' && cur_c == '*') { //进入多行注释中
j--;
in_comment = 1;
}
else if (old_c == '/' && cur_c == '/') { //进入单行注释中
j--;
in_comment = 2;
}
else if (isspace(cur_c)) {
//若为空白字符,则不存入data中
}
else { //其他情况则直接将数据写入data中
data[j++] = cur_c;
}
break;
case 1:if (old_c == '*' && cur_c == '/') in_comment = 0; //多行注释结束
break;
case 2:if (i == strlen(buff)) in_comment = 0; //单行注释到这行结束时标志位置为0
break;
case 3:
data[j++] = cur_c;
if (cur_c == '\"') in_comment = 0;
break;
case 4:
data[j++] = cur_c;
if (cur_c == '\'') in_comment = 0;
break;
}
old_c = cur_c; //保留上一个字符
}
if (j > 0) { //若这一行处理过后的data数组有数据,则读出到文件中
if (!first) {
fout << '\n';
}
else first = false;
for (int k = 0; k < j; k++) {
fout << data[k];
}
}
i = j = 0; //读取新的一行数据前,这些变量先进行重置
}
if (in_comment != 0) fout << '\n' << "error"; //若标志位不等于0,则说明多行注释不到位,没有结束标志
}
int main() {
ifstream fin("input.txt");
while (!fin.is_open()) {
cout << "文件不存在!";
return 0;
}
ofstream fout("output.txt");
pre_process(fin, fout);
fin.close(); fout.close();
return 0;
}