2016-08-01 85 views
-3

我想找到最有效的方式來從字符串中刪除標點符號在c + +,這是我目前有。最有效的方式來從字符串中刪除標點符號在c + +

#include <iostream> 
#include <string> 
#include <fstream> 
#include <iomanip> 
#include <stdlib.h> 
#include <algorithm> 

using namespace std; 

void PARSE(string a); 

int main() 
{ 
    string f; 
    PARSE(f); 
    cout << f; 
} 

void PARSE(string a) 
{ 
    a = "aBc!d:f'a"; 

    a.erase(remove_if(a.begin(), a.end(), ispunct), a.end()); 

    cout << a << endl; 
} 

有沒有更簡單/更有效的方法來做到這一點?

我在想使用str.len,獲取字符串的長度,通過for循環運行它並檢查ispunct,然後刪除它。

+5

「_I正在考慮使用str.len,獲取字符串的長度,通過for循環運行並檢查ispunct然後刪除它。」這幾乎就是您的'erase'和'remove_if'調用的內容這樣做。與使用高度優化,經過嚴格測試的標準庫函數相比,您認爲自己做這件事更容易,更有效,或者更少出錯。 –

+1

是什麼讓你覺得這樣使用[* erase-remove idiom *](https://en.wikipedia.org/wiki/Erase-remove_idiom)不會是最「有效」的方式?你是否認爲這是你程序中的瓶頸?就像前面的評論者說的那樣,試圖自己實現這一點將會變得更加混亂,並且更容易出錯和錯誤。 –

+0

尋找這個問題的一部分,它沿着*「我知道有一個更有效的方法來做到這一點,它是什麼?」*如上面2條評論所暗示的。只找到問題*「有沒有更簡單/更有效的方法來做到這一點?」* –

回答

1

沒有字符串副本。沒有堆分配。沒有堆重新分配。

void strip_punct(string& inp) 
{ 
    auto to = begin(inp); 
    for (auto from : inp) 
     if (!ispunct(from)) 
      *to++ = from; 
    inp.resize(distance(begin(inp), to)); 
} 

相較於:

void strip_punct_re(string& inp) 
{ 
    inp.erase(remove_if(begin(inp), end(inp), ispunct), end(inp)); 
} 

我創造了各種工作負載。作爲基準輸入,我創建了一個字符串,其中包含32到127之間的所有字符值。我附加了這個字符串num -times來創建我的測試字符串。我將strip_punctstrip_punct_re都與測試字符串iters -times的副本進行了通話。我每次測試執行10次這些工作負載。我在放棄最低和最高的結果之後對時間進行平均。我使用Microsoft Surface Book 4(Skylake)上的Windows 10上的VS2015使用發佈版本(優化版)進行了測試。 I SetPriorityClass()用於HIGH_PRIORITY_CLASS的處理,並使用QueryPerformanceFrequency/QueryPerformanceCounter對結果計時。所有的時序都沒有附加調試器。

num  iters  seconds  seconds (re) improvement 
10000  1000  2.812  2.947    4.78% 
1000  10000  2.786  2.977    6.85% 
    100  100000  2.809  2.952    5.09% 

通過改變NUM和iters同時保持處理的字節相同的數,我能看到的成本主要由處理而不是每個調用開銷字節數的影響。讀取反彙編證實了這一點。

所以這個版本的速度快了5%,並且產生了30%的代碼。

+1

這是否會讓您過度/刪除? –

+0

另外,我看不到您是否正在測試版本,優化版本或調試,未優化版本。如果是後者,那麼你的結果是沒有意義的。 – PaulMcKenzie

+0

已更新,其中包含發佈版本註釋 –