細節問題

 

 

  1.     今天看了下,大一時寫的C程序,雖然命名真的不太規範,但整體感覺還好,程序邏輯很清
  2. 晰、也比較高效。這的確是我編程的風格,呵呵。我不太喜歡很臃腫的代碼,喜歡將它們寫得足夠
  3. 簡潔,而邏輯上也足夠清晰。
  4.     舉個小小的例子,一個大家熟知的 split 函數,它完成的功能就是:
  5. 給定一個字符串,然後通過指定的分隔符,將字符串分成N個子串,就這麼簡單。
  6.     現在給出程序1
  7. void Split( const string& s, char c, vector<string>& v )
  8. {
  9.     int i = 0;
  10.     int j = s.find(c,0);
  11.     while (j >= 0) 
  12.     {
  13.         v.push_back(s.substr(i, j-i));
  14.         i = ++j;
  15.         j = s.find(c, j);
  16.         if (j < 0)
  17.         {
  18.             v.push_back(s.substr(i, s.length( )));
  19.         }
  20.     }
  21. }
  22.     第一眼看它的時候,你或許會納悶 爲什麼會有這個 if (j < 0),你試下 去掉這條語句,
  23. 就會發現一個bug,就是最後條子串不會被添加到 v 中,例如: s = "ht;t2;t3;t4", c = ';'時,
  24. 調用Split時,t4就不會加到v中。
  25. 原因很簡單:在 i 指向 't'的時候,這條語句 j = s.find( c, j ); 會因爲找不到 ';' 而返回 
  26. -1。
  27. 但是這個函數的寫作者知道了這種情況,在後面添加了 if ( j < 0 ) ...解決了這個bug。。。
  28. 是這樣的嗎?可別被我誘導了,實際上真正的bug在於當字符串裏面沒有 ';'時,問題就來了,例如
  29. : s = "http", c = ';'int j = s.find(c,0); 執行後 j = -1; while根本不會運行,也就是說
  30. ,v裏面根本就沒有數據了。顯然這和該函數完成的功能是不吻合的。
  31. 實際上,通過分析上面的程序,我們發現我們只是漏掉了最後一個子串的情況,因此,別的代碼不
  32. 用做改變,只用在最後將 s 裏的最後一個子串 插入到 v 中就OK了。
  33. 我們可以先去掉這個 while 裏邊的 if 。 然後在while()外面,將最後的那個子串插入到 v 中,
  34. 這顯然可行。而且,比上面的效率要高。修改之後的程序2爲:
  35. 程序2:
  36. void Split( const string& s, char c, vector<string>& v )
  37. {
  38.     int i = 0;
  39.     int j = s.find(c,0);
  40.     while (j >= 0) 
  41.     {
  42.         v.push_back(s.substr(i, j-i));
  43.         i = ++j;
  44.         j = s.find(c, j);
  45.     }
  46. v.push_back( s.substr(i, -1) );
  47. }
  48. 最後一句代表把 s.substr(i,-1)表示從下標i 開始到 s結尾處 的一個子串。顯然在字符串分隔符
  49. 很多的情況下,它比程序一節省了將近一半的時間。
  50. 在這裏,你可能會說我太拘泥於細節了。的確,有時候,編程的確需要有很好的細節把握能力,但
  51. 這並不是過分的表現。可以這麼說,不會把握細節的程序員,不是一個好的程序員。
  52. 回到正題,我甚至覺得上面那段還是不大好看,能不能再簡潔些呢。我們仔細分析下,可發現,只
  53. 要 s 不爲空的情況下,
  54. v裏面的子串就至少有一個,也就是說,循環至少應該被執行一次。那個循環與此相同,對!用 do 
  55. .. while循環。我將修改後的代碼直接給出:
  56. 程序3:
  57. void Split( const string& s, char c, vector<string>& v )
  58. {
  59.     if ( s.empty() )
  60.     return;
  61.     int i;
  62.     int j = -1;
  63.     do
  64.     {
  65.         i = ++j;    
  66.         j = s.find( c, j );
  67.         v.push_back( s.substr(i, j-i) );
  68.     } while ( j > 0 );
  69. }
  70. 你可能會擔心在 j < 0(也就是j==-1) 之後,v.push_back(s.substr(i, j-i)); 是否正確。
  71. 是的,當 j = -1 時,j - i 顯然是一個負數,在這樣的情況下,s.substr將包含從下標從 i 到 s
  72. 結尾處 的 子串
  73. 這樣做,感覺上就比較清晰了。

 

發佈了32 篇原創文章 · 獲贊 24 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章