好久沒寫文章了,今天又來做個學習C++的小總結。
一、統計代碼行數
幾個星期前做了個統計代碼的小程序,對文件的批處理需要獲取文件列表,因為是在windows下操作的,所以百度到一個系統調用
system("dir /a /b >> file_list.txt");
功能就是把當前目錄下的所有文件名寫到file_list.txt文件中去。這樣我就得到了所有的文件名,從而就可以對文件批處理了。對每一個文件的操作就是首先讀取文件名,然后就打開文件,接着一行一行的讀文件,沒讀取一行文件就累計代碼行數。過程很簡單,代碼如下:
1 #include <iostream> 2 #include <fstream> 3 #include <cstdlib> 4 5 using std::cout; 6 using std::endl; 7 using std::fstream; 8 using std::string; 9 10 int main(int argc, char **argv) 11 { 12 //創建文件名列表文件,若存在則清空文件 13 fstream file_list("file_list.txt",std::ios::out); 14 file_list.close(); 15 16 //寫入文件名列表到file_list.txt 17 system("dir /a /b >> file_list.txt"); 18 19 long sum_code = 0; 20 fstream code_file; 21 file_list.open("file_list.txt", std::ios::in); 22 string str_line = ""; 23 string t_str = ""; 24 unsigned int loc = 0;//查找文件名中的"." 25 string str_last = ""; 26 27 while (!file_list.eof()) 28 { 29 getline(file_list,str_line); 30 loc = str_line.find(".",0); 31 // cout << "loc = " << loc << endl; 32 if (loc != string::npos) 33 { 34 str_last = str_line.substr(loc); 35 // cout << "str_last = " << str_last << endl; 36 } 37 else 38 { 39 continue; 40 } 41 42 if (str_last.compare(".h") == 0 43 || str_last.compare(".c") == 0 44 || str_last.compare(".cpp") == 0) 45 { 46 code_file.open(str_line.c_str(),std::ios::in); 47 cout << "文件名 : " << str_line << endl; 48 } 49 else 50 { 51 continue; 52 } 53 54 //讀文件行數 55 while (!code_file.eof()) 56 { 57 getline(code_file,t_str); 58 cout << t_str << endl; 59 sum_code++; 60 } 61 code_file.close(); 62 cout << endl; 63 } 64 file_list.close(); 65 66 cout << "代碼行數:" << sum_code << endl; 67 system("pause"); 68 69 return 0; 70 }
二、批量刪除文件中的某一行
今天做的修改時有原因的,因為我正在將http://www.cplusplus.com/reference/做成一個chm文件(供離線查尋的文檔)。通過Teleport Ultra軟件獲取到網站的代碼后,代碼有好多是404頁面和用戶登錄頁面。這些文件我是通過手工刪除的,刪除404頁面就是根據文件大小來刪除的(不會傻到對着一千多個文件一個一個打開查看,畢竟404頁面大小是一樣的)。刪除登錄頁面是根據文件名的。文件名有new.cgi?或者edit.cgi?等等,是按文件名排序刪除的。
然后使用EasyCHM軟件開始制作。制作后出現了問題,打開頁面預覽出現
我郁悶了,我就打開源代碼,找到了有這么一行,打開每一文件都這樣。
因此,我就想到之前寫的代碼統計的程序了,然后我就做了個微小的修改把這一行刪除掉。在上面的55行的while中加入
if (t_str == "onPrint.print();") { cout << t_str << endl; continue; }
因為要修改源文件,我就通過一個臨時文件來存儲修改后的文件,文件修改完成后再將臨時文件的內容復制到源文件中,復制文件的代碼段:
//復制回來 out_tmp.open("tmp",std::ios::in); code_file.open(str_line.c_str(),std::ios::out); char ch; while(code_file && out_tmp.get(ch)) { code_file.put(ch); } code_file.close(); out_tmp.close(); cout << "修改" << str_line << "完成" << endl;
全部代碼如下:

1 #include <iostream> 2 #include <fstream> 3 #include <cstdlib> 4 5 using std::cout; 6 using std::endl; 7 using std::fstream; 8 using std::string; 9 10 int main(int argc, char **argv) 11 { 12 //創建文件名列表文件,若存在則清空文件 13 fstream file_list("file_list.txt",std::ios::out); 14 file_list.close(); 15 16 //寫入文件名列表到file_list.txt 17 system("dir /a /b >> file_list.txt"); 18 19 long sum_code = 0; 20 fstream code_file; 21 file_list.open("file_list.txt", std::ios::in); 22 string str_line = ""; 23 string t_str = ""; 24 unsigned int loc = 0;//查找文件名中的"." 25 string str_last = ""; 26 27 while (!file_list.eof()) 28 { 29 getline(file_list,str_line); 30 loc = str_line.find(".",0); 31 // cout << "loc = " << loc << endl; 32 if (loc != string::npos) 33 { 34 str_last = str_line.substr(loc); 35 // cout << "str_last = " << str_last << endl; 36 } 37 else 38 { 39 continue; 40 } 41 42 if (str_last.compare(".htm") == 0) 43 { 44 code_file.open(str_line.c_str(),std::ios::in); 45 cout << "文件名 : " << str_line << endl; 46 } 47 else 48 { 49 continue; 50 } 51 52 fstream out_tmp("tmp",std::ios::out); 53 //讀文件行數 54 while (!code_file.eof()) 55 { 56 getline(code_file,t_str); 57 if (t_str == "onPrint.print();") 58 { 59 cout << t_str << endl; 60 continue; 61 } 62 out_tmp << t_str << endl; 63 sum_code++; 64 } 65 code_file.close(); 66 out_tmp.close(); 67 cout << endl; 68 69 //復制回來 70 out_tmp.open("tmp",std::ios::in); 71 code_file.open(str_line.c_str(),std::ios::out); 72 char ch; 73 while(code_file && out_tmp.get(ch)) 74 { 75 code_file.put(ch); 76 } 77 code_file.close(); 78 out_tmp.close(); 79 cout << "修改" << str_line << "完成" << endl; 80 } 81 file_list.close(); 82 83 cout << "代碼行數:" << sum_code << endl; 84 system("pause"); 85 86 return 0; 87 }
三、批量刪除文件中的某一代碼段
這樣對所有文件批處理后又有了新問題,彈出的腳本對話框和上面的類似。這樣慢慢刪豈不會累死,我能不能把所有的<script></<script>都刪除掉呢?我就先手動刪除一個文件的所有<script> ... </<script>。然后放到EasyCHM軟件中,結果真的好了,不彈出腳本錯誤對話框了(腳本都沒了,何來腳本錯誤呢?)。這樣我就放心了,因為腳本文件刪除了不影響htm文件的界面。這樣我就開始修改代碼了,同樣修改讀文件那一段代碼。
if (t_str.substr(0,7) == "<script") { while (!code_file.eof() && t_str != "</script>" && t_str.substr(t_str.size()>9?t_str.size()-9:0) != "</script>") { cout << t_str << endl; getline(code_file,t_str); } cout << t_str << endl; getline(code_file,t_str); }
這是放在讀文件循環中的代碼。每次讀到一行的頭幾個字符是"<script"就對接下來的字符處理知道讀到"</script>"。因為我查了所有代碼都類似,"<script"在每行的行首,"</script>"在字符串的末尾后者行首,所以就只是簡單的判斷了下,沒有考慮到一行中既有腳本文件又有非腳本文件的情況:
<script type="text/javascript">google_ad_height = 60;</script><div id="I_midclear"></div> </div><script type="text/javascript"src="show_ads.js" tppabs="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
我想也不會有人會把這種代碼寫成一行吧。接着就測試了一個htm文件,結果可以了,只是有一個bug,運行一次后還殘留着<script> ... </<script>。再運行一次就清理完了。先看有bug的代碼:

1 #include <iostream> 2 #include <fstream> 3 #include <cstdlib> 4 5 using std::cout; 6 using std::endl; 7 using std::fstream; 8 using std::string; 9 10 int main(int argc, char **argv) 11 { 12 //創建文件名列表文件,若存在則清空文件 13 fstream file_list("file_list.txt",std::ios::out); 14 file_list.close(); 15 16 //寫入文件名列表到file_list.txt 17 system("dir /a /b >> file_list.txt"); 18 19 long sum_code = 0; 20 fstream code_file; 21 file_list.open("file_list.txt", std::ios::in); 22 string str_line = ""; 23 string t_str = ""; 24 unsigned int loc = 0;//查找文件名中的"." 25 string str_last = ""; 26 27 while (!file_list.eof()) 28 { 29 getline(file_list,str_line); 30 loc = str_line.find(".",0); 31 // cout << "loc = " << loc << endl; 32 if (loc != string::npos) 33 { 34 str_last = str_line.substr(loc); 35 // cout << "str_last = " << str_last << endl; 36 } 37 else 38 { 39 continue; 40 } 41 42 if (str_last.compare(".htm") == 0) 43 { 44 code_file.open(str_line.c_str(),std::ios::in); 45 cout << "文件名 : " << str_line << endl; 46 } 47 else 48 { 49 continue; 50 } 51 52 fstream out_tmp("tmp",std::ios::out); 53 //讀文件行數 54 while (!code_file.eof()) 55 { 56 getline(code_file,t_str); 57 if (t_str.substr(0,7) == "<script") 58 { 59 while (!code_file.eof() 60 && t_str != "</script>" 61 && t_str.substr(t_str.size()>9?t_str.size()-9:0) != "</script>") 62 { 63 cout << t_str << endl; 64 getline(code_file,t_str); 65 } 66 cout << t_str << endl; 67 getline(code_file,t_str); 68 } 69 out_tmp << t_str << endl; 70 sum_code++; 71 } 72 code_file.close(); 73 out_tmp.close(); 74 cout << endl; 75 76 //復制回來 77 out_tmp.open("tmp",std::ios::in); 78 code_file.open(str_line.c_str(),std::ios::out); 79 char ch; 80 while(code_file && out_tmp.get(ch)) 81 { 82 code_file.put(ch); 83 } 84 code_file.close(); 85 out_tmp.close(); 86 cout << "修改" << str_line << "完成" << endl; 87 } 88 file_list.close(); 89 90 cout << "代碼行數:" << sum_code << endl; 91 system("pause"); 92 93 return 0; 94 }
接下來就是查找bug了,然后在解決bug,記住哦,做這些操作記得備份之前原版的htm文件哦,要不然你弄完后原版的文件沒了怎么來找bug,怎么測試啊。關鍵還是看這里(循環讀文件人后再判斷的代碼段):
1 fstream out_tmp("tmp",std::ios::out); 2 //讀文件行數 3 while (!code_file.eof()) 4 { 5 getline(code_file,t_str); 6 if (t_str.substr(0,7) == "<script") 7 { 8 while (!code_file.eof() 9 && t_str != "</script>" 10 && t_str.substr(t_str.size()>9?t_str.size()-9:0) != "</script>") 11 { 12 cout << t_str << endl; 13 getline(code_file,t_str); 14 } 15 cout << t_str << endl; 16 getline(code_file,t_str); 17 } 18 out_tmp << t_str << endl; 19 sum_code++; 20 } 21 code_file.close(); 22 out_tmp.close(); 23 cout << endl;
要修改這段代碼,需要來查看結果的,我把運行一次后的結果和原始文件對比了下,結果如下:
發現了問題,是因為執行了一次刪除腳本后,接下來的腳本緊接在其下一行,讀取的時候跳過了這一次檢查,這樣簡單啊,只執行一次判定<script>,我把if改成while就可以了,修改后的代碼如下:

1 #include <iostream> 2 #include <fstream> 3 #include <cstdlib> 4 5 using std::cout; 6 using std::endl; 7 using std::fstream; 8 using std::string; 9 10 int main(int argc, char **argv) 11 { 12 //創建文件名列表文件,若存在則清空文件 13 fstream file_list("file_list.txt",std::ios::out); 14 file_list.close(); 15 16 //寫入文件名列表到file_list.txt 17 system("dir /a /b >> file_list.txt"); 18 19 long sum_code = 0; 20 fstream code_file; 21 file_list.open("file_list.txt", std::ios::in); 22 string str_line = ""; 23 string t_str = ""; 24 unsigned int loc = 0;//查找文件名中的"." 25 string str_last = ""; 26 27 while (!file_list.eof()) 28 { 29 getline(file_list,str_line); 30 loc = str_line.find(".",0); 31 // cout << "loc = " << loc << endl; 32 if (loc != string::npos) 33 { 34 str_last = str_line.substr(loc); 35 // cout << "str_last = " << str_last << endl; 36 } 37 else 38 { 39 continue; 40 } 41 42 if (str_last.compare(".htm") == 0) 43 { 44 code_file.open(str_line.c_str(),std::ios::in); 45 cout << "文件名 : " << str_line << endl; 46 } 47 else 48 { 49 continue; 50 } 51 52 fstream out_tmp("tmp",std::ios::out); 53 //讀文件行數 54 while (!code_file.eof()) 55 { 56 getline(code_file,t_str); 57 while (t_str.substr(0,7) == "<script") 58 { 59 while (!code_file.eof() 60 && t_str != "</script>" 61 && t_str.substr(t_str.size()>9?t_str.size()-9:0) != "</script>") 62 { 63 cout << t_str << endl; 64 getline(code_file,t_str); 65 } 66 cout << t_str << endl; 67 getline(code_file,t_str); 68 69 } 70 out_tmp << t_str << endl; 71 sum_code++; 72 } 73 code_file.close(); 74 out_tmp.close(); 75 cout << endl; 76 77 //復制回來 78 out_tmp.open("tmp",std::ios::in); 79 code_file.open(str_line.c_str(),std::ios::out); 80 char ch; 81 while(code_file && out_tmp.get(ch)) 82 { 83 code_file.put(ch); 84 } 85 code_file.close(); 86 out_tmp.close(); 87 cout << "修改" << str_line << "完成" << endl; 88 } 89 file_list.close(); 90 91 cout << "代碼行數:" << sum_code << endl; 92 system("pause"); 93 94 return 0; 95 }
最后,我也完成了http://www.cplusplus.com/reference/離線chm版本。大家玩這個注意備份文件哦!!!
附件:
[1] 統計代碼行數
[2] 刪除htm文件中腳本代碼段
[3] c++標准參考文檔離線chm版