去注释程序
C/C++中注释有两种形式:
1./* … */
2.// …
我们要实现的功能就是讲程序中的注释过滤掉。
我们首先采用一种直接的方法进行过滤,就是顺序扫描整个源代码,检测 /*、*/、// 这些标示,以获取程序的注释。
// 程序1:顺序扫描 #include <iostream> #include <string> #include <fstream> #include <vector> using namespace std; void read_prog(const string& file, string& prog) { ifstream fin(file.c_str()); if (!fin) { cerr << file << " error!" << endl; exit(2); } prog.clear(); string line; while (getline(fin, line)) { prog += line + ' '; } } void filter(const string& prog, string& prog_filtered, vector<string>& comments) { prog_filtered.clear(); comments.clear(); char ch = 0; for (string::size_type i = 0; i < prog.size(); ) { string tmp; ch = prog[i]; if (ch == '/') { tmp += ch; ++i; if (i >= prog.size()) { prog_filtered += tmp; return; } ch = prog[i]; if (ch == '*') { tmp += ch; ++i; string::size_type pos = prog.find("*/", i); if (pos < prog.size()) { tmp += prog.substr(i, pos - i + 2); i = pos + 2; comments.push_back(tmp); } else { tmp += prog.substr(i); i = prog.size(); prog_filtered += tmp; } } else if (ch == '/') { tmp += ch; ++i; string::size_type pos = prog.find(' ', i); tmp += prog.substr(i, pos - i); i = pos; comments.push_back(tmp); } else { tmp += ch; ++i; prog_filtered += tmp; tmp.clear(); } } else { tmp += ch; ++i; prog_filtered += tmp; tmp.clear(); } } } int main() { string prog, prog_filtered; vector<string> comments; read_prog("prog.txt", prog); cout << prog << endl; filter(prog, prog_filtered, comments); cout << prog_filtered << endl; for (vector<string>::size_type i = 0; i != comments.size(); ++i) { cout << i + 1 << ':' << comments[i] << endl; } return 0; }
测试样例:
#include <iostream> using namespace std; /// test1 //* test2*/ // main函数 int main() { /* 主函数 */ /* *注释 */ } // 阿萨德发生的发生地方 /* asdfasdf *
做法2:利用状态转换图
// 程序2:利用状态转换图进行注释的过滤 #include <iostream> #include <string> #include <fstream> #include <vector> using namespace std; void read_prog(const string& file, string& prog) { ifstream fin(file.c_str()); if (!fin) { cerr << file << " error!" << endl; exit(2); } prog.clear(); string line; while (getline(fin, line)) { prog += line + ' '; } } void StateTransitionDiagram(const string& prog, string& prog_filtered, vector<string>& comments) { int state = 1; string tmp; for (string::size_type i = 0; i < prog.size(); ++i) { char ch = prog[i]; switch (state) { case 1: if (ch == '/') { tmp += ch; state = 2; } else { prog_filtered += ch; } break; case 2: if (ch == '*') { tmp += ch; state = 3; } else if (ch == '/') { tmp += ch; state = 5; } else { tmp += ch; prog_filtered += tmp; tmp.clear(); state = 1; } break; case 3: if (ch == '*') { tmp += ch; state = 4; } else { tmp += ch; } break; case 4: if (ch == '/') { tmp += ch; comments.push_back(tmp); tmp.clear(); state = 1; } else { tmp += ch; state = 3; } break; case 5: if (ch == ' ') { comments.push_back(tmp); tmp.clear(); state = 1; --i; } else { tmp += ch; } break; default: cerr << "Error!" << endl; break; } } } int main() { string prog, prog_filtered; vector<string> comments; read_prog("prog.txt", prog); cout << prog << endl; StateTransitionDiagram(prog, prog_filtered, comments); cout << prog_filtered << endl; for (vector<string>::size_type i = 0; i != comments.size(); ++i) { cout << i + 1 << ':' << comments[i] << endl; } return 0; }
测试样例:
#include <iostream> using namespace std; /// test1 //* test2*/ // main函数 int main() { /* 主函数 */ /* *注释 */ } // 阿萨德发生的发生地方 /* asdfasdf *
总结
上文利用两种方法进行两种注释的过滤,第一种方式是顺序扫描程序,当检测到/、*等字符时进行检测判断,对符合条件的注释进行提取。
第二种方法是借助了状态转换图,设置扫描程序中根据不同字符设置当前状态值state,根据当前状态state以及当前字符进行判断,对符合条件的注释进行提取过滤。
第一种方法是仅仅利用了当前字符的特性,在当前字符条件下进行后续的处理。第二种方法除了利用当前字符的特性外,还结合了检测的状态,这样记录的信息更多,使得程序处理逻辑更为简单清晰,更有利于逻辑的划分和程序的书写,同时也提高了代码的可读性。
第一种方法是if的嵌套,多层if。第二种方法利用了switch-case语句(也可以是if语句)使得处理逻辑得以平铺,整个处理流程更为清晰易懂。这可能就是状态转换图的优点之所在。
数据结构决定算法,增加信息表示方法和途径,使得信息处理更为简单易行。预处理的思想也就在于增加信息表达方式,使得后续处理更为快捷和方便。