2013-02-01 83 views
0

我試圖做一個函數來拆分一個字符串,「拆分空間」,到一個向量將包含「拆分」「在」「空間」。到目前爲止,這是我得到的代碼。拆分函數拋出錯誤

#include <iostream> 
#include <utility> 
#include <algorithm> 

using namespace std; 

std::vector<std::string> split(std::string * s, char * tosplit) 
{ 
    size_t i = 0; 
    int count = 0; 
    size_t contain; 
    std::vector<std::string> split; 

    std::cout << "Start" << std::endl; 
    std::cout << *s << std::endl; 
    std::cout << *tosplit << std::endl; 

    while((contain = s->find(*tosplit,i)) != std::string::npos) 
    { 
     count++; 
     i = contain + 1; 
    } 

    std::cout << "Contains " << count << std::endl; 

    if (count == 0) 
    { 
     std::cout << "Equals 0" << std::endl; 
     split = std::vector<std::string>(1); 
     split.at(0) = s->c_str(); 
     return split; 
    } 

    split = std::vector<std::string>(count + 1); 
    split.begin(); 

    int lasti; 
    i = s->find_first_of(*tosplit); 
    split.at(0) = s->substr(0, i); 
    lasti = i; 
    int runs = 1; 

    while (runs <= count) 
    { 
     i = s->find(*tosplit, lasti + 1); 
     std::cout << i << " " << lasti << std::endl; 
     split.at(runs) = s->substr(lasti, --i); 
     runs++; 
     lasti = i; 
    } 

    split.at(runs) = s->substr(lasti, s->size()); 

    std::cout << "done, result is" << std::endl; 
    i = 0; 
    while (i < split.capacity()) 
    { 
     std::cout << split.at(i) << std::endl; 
     i++; 
    } 

    return split; 
} 

它拋出一個out_of_range異常。任何幫助,你可以給予讚賞。這就像我在函數中使用指針的第一部分,所以我在這裏猜測。
謝謝!

請不要建議使用x或y方法,我想寫我自己的,因爲我正在爲了體驗而做。

+5

你爲什麼用'std :: string'指針? – Rapptz

+0

您不需要將char作爲指針傳遞。 –

+0

當你使用調試器時,哪一行會拋出異常? –

回答

0

單分隔符:

你寫太多太多的代碼來做到這一點。你可以做幾行。你得到非常複雜的。而且沒有理由對這個指針做任何事情。

vector<string> Split(string s, char delim) 
{ 
    vector<string> strings; 
    for(istringstream ss(s); getline(ss, s, delim); strings.push_back(move(s))); 
    return strings; 
} 

多個分隔符:

一種用於使用多個分隔符是更復雜的解決方案。您不能再利用getline,這意味着您基本上自己編寫了getline的部分功能。但是,它仍然很短。

vector<string> Split(const string& s, const char* delims) 
{ 
    vector<string> strings; 

    for(string::size_type start = 0, end; end != string::npos && start < s.size(); start = end+1) 
    { 
     end = s.find_first_of(delims, start); 
     strings.push_back(s.substr(start, end-start)); 
    } 

    return strings; 
} 

這會在分隔符彼此相鄰時添加空白字符串。如果這不是相鄰分隔符所需的行爲,則可以通過使用if(start != end)來防止push_back而輕易避免。

結論:

當你開始寫這樣一個低水平的算法,它在廣義上的僞代碼,然後編寫任何代碼前檢查一下C++標準庫可以提供切口部或者你所有的工作。你最終會得到更小,更少的錯誤和更易於理解的代碼。例如,沒有人希望看到find_first_of的手動執行。閱讀文字find_first_of要清楚得多。很明顯,這個功能將做什麼,並且它沒有bug(希望)。

+0

耶穌我完全錯過了這一點。有兩種方法可以分割兩個分隔符嗎? (ex +和一個空格 – Tips48

+0

@ Tips48我編輯了我的答案,包括一個解決方案的多個分界點 – David

+0

謝謝,看起來不錯 – Tips48

1

這實際上很容易處理,例如, std::istringstreamstd::copy,以及來自standard iterator library的一些幫助。

對於那些想看到工作代碼的人,可以找到here

對於鏈接中的代碼,整個程序是18行,其中實際分割是三行,但這是因爲我分割它使它更易讀(它實際上是一個單一的函數調用)。


對於更通用的解決方案,並且如果C++ 11 regular expressions是可用的(或Boost regex,或一些其它正則表達式庫是可用的),可以用來給。

+0

「請不要建議使用x或y方法,我想寫我自己,因爲我正在爲體驗做這件事。」 – Rapptz

+0

我打算髮布常見問題解答條目,直到我看到帖子的最後一行。不過,它們可以用於啓發。 – chris

+0

@Rapptz糟糕,沒有看到第一個,更新我的答案,以刪除代碼。 –

0

而不是試圖爲您的向量預先分配空間,只需使用push_back追加部分,因爲你找到它們。

+0

不知道你能做到這一點,謝謝 – Tips48

0

對不起,但我忍不住想你的功能過於複雜。如果你想自己編寫邏輯進行學習,而不是使用一些預先包裝的功能,那很好,但這並不意味着你不應該保持你的邏輯簡單

我相信你的算法應該看起來更像這個:

// Note that the delimiter can be a string as well, not just a char 
vector<string> split(string const& s, string const& delimiter) 
{ 
    vector<string> result; 

    string::size_type startPos = 0; 
    string::size_typepos = s.find(delimiter); 
    while (pos != string::npos) 
    { 
     // Extract token and save it... 
     string token = s.substr(startPos, pos - startPos); 
     result.push_back(token); 

     // Step to next token... 
     startPos = pos + 1; 
     pos = s.find(delimiter, pos + 1); 
    } 

    // Parse last token (in case the string is not terminated 
    // by the delimiter). 
    if (startPos < s.length()) 
    { 
     string lastToken = s.substr(startPos); 
     result.push_back(lastToken); 
    } 

    return result; 
} 
1

這裏有一些問題我已經找到:

  1. 檢查NULL指針之前取消引用s
  2. 在檢查NULL之前取消引用tosplit
  3. 除了計算字符串的數量,然後拆分 字符串(需要2次搜索)之外,在搜索時計數。
  4. 當您將其 傳遞給while循環中的表達式時,位置i = contain + 1可能超出範圍。
  5. 嘗試使用方法std::vector::push_back,而不是在特定(可能未分配)的位置分配 。
  6. 語句return split返回字符串數組的副本。 你真的想要返回一個大的數據結構嗎?
  7. 語句split.begin()返回一個迭代器到矢量的開頭 ;你不使用。
  8. 使用split.size()不是split.capacity。他們是兩種不同的概念。