2009-05-26 283 views
1

我有這段代碼來分割一個字符串。出於某種原因,它只是坐在那裏無所事事。我不確定問題是什麼。順便說一下,這裏是。分割一個字符串

vector<string> split(const string &str, const char &delim) 
{ 
    typedef string::const_iterator iter; 

    iter beg = str.begin(); 

    vector<string> tokens; 

    while(beg != str.end()) 
    { 
     iter temp = find(beg, str.end(), delim); 
     if(beg != str.end()) 
      tokens.push_back(string(beg, temp)); 
     beg = temp; 
    } 

    return tokens; 
} 
+1

順便說一句,在while循環內測試「beg!= str.end()」沒有意義。自從環路頂部開始測試條件後,您還沒有更改過乞討或str。此外,通過值而不是const引用傳遞char更爲常見。這些都不是bug,它們只是讓你的代碼更簡單易讀,而不會影響行爲。 – 2009-05-26 11:16:54

回答

1

find()將返回下一個標記的位置X.當你分配這個乞求並進入下一次迭代時,它將再次開始在位置X上搜索 - 再一次 - 也是一次......也就是說,你陷入了一個無限循環。

試試這個代碼:

vector<string> split(const string &str, const char &delim) 
{ 
    typedef string::const_iterator iter; 

    vector<string> tokens; 
    iter pos = str.begin(), last = str.begin(); 

    while(pos != str.end()) { 
     last = pos; 
     pos = find(pos, str.end(), delim); 

     if (pos != str.end()) { 
      string token = string(last, pos); 
      if (token.length() > 0) 
       tokens.push_back(token); 

      last = ++pos; 
     } 
    } 

    string lastToken = string(last, pos); 
    if (lastToken.length() > 0) 
     tokens.push_back(lastToken); 

    return tokens; 
} 

這額外的好處,這將包括在列表中的最後一個令牌(例如,在空間分割時,字符串「abc」現在將返回令牌A,B和c而不是隻有a和b),並且多個分隔符不會導致空的標記。

6

可能調試它給你,我想,但從長遠來看,這並不會幫助你。這就是你所做的。

在每行之後,將printf()或cout staement將已更改的變量轉儲到標準輸出。然後運行你的代碼,將一組簡單的參數傳遞給它:

vector<string> x = split ("Hello there, Bob.", ' '); 

然後,檢查輸出,看看爲什麼你的實現不工作。你可能不得不跳出代碼,因爲如果它只是坐在那裏,你可能已經讓自己陷入了新的無限循環之中。

授人以魚,他會吃了一天,教一個人魚,他永遠不會再捱餓。

或者特里·普拉切特版本:

給一個人一些火,他會一天是溫暖的,設置人火,他會熱情爲其餘他的生命。

更新:

既然你說,你究竟做了什麼,我認爲,這裏是從做發現。很明顯,當您在while循環的末尾設置begtemp時,它指向空間。這是通過在while循環的頂部打印beg字符串發現的 - 在提取第一個單詞後它從未改變。

然後,當您執行下一個find時,它會發現完全相同的空間,而不是首先跳過空格,然後正確調用find。您需要跳過每個find之後的空格,確保您不會迭代超過字符串的末尾。

這是我的解決方案。如你所願使用它。

#include <iostream> 
#include <string> 
#include <vector> 
#include <algorithm> 
using namespace std; 

vector<string> split(const string &str, const char &delim) { 
    typedef string::const_iterator iter; 
    iter beg = str.begin(); 
    vector<string> tokens; 

    while(beg != str.end()) { 
     //cout << ":" << beg._Myptr << ":" << endl; 
     iter temp = find(beg, str.end(), delim); 
     if(beg != str.end()) 
      tokens.push_back(string(beg, temp)); 
     beg = temp; 
     while ((beg != str.end()) && (*beg == delim)) 
      beg++; 
    } 

    return tokens; 
} 

int main() { 
    vector<string> x = split ("Hello, my name is Bob. ", ' '); 
    return 0; 
} 

沒有在while循環結束這個空間跳躍代碼,輸出爲:

:Hello, my name is Bob. : 
: my name is Bob. : 
: my name is Bob. : 
: my name is Bob. : 
: my name is Bob. : 
: my name is Bob. : 
: my name is Bob. : 
: my name is Bob. : 

等,循環往復。 隨着跳躍代碼,您可以:

:Hello, my name is Bob. : 
:my name is Bob. : 
:name is Bob. : 
:is Bob. : 
:Bob. : 
+0

是的,這正是我發佈之前所做的,抱歉,因爲某些原因,它在無限循環中,我認爲這是因爲Charles Bailey指出的。 我試過了= ++ temp以便在分隔符之後乞求字符但仍然彈出.. – 2009-05-26 07:20:21

+0

那裏有好語錄:) – xtofl 2009-05-26 08:42:39

+0

我也喜歡,「給一個人一條魚,他會吃一天,給他一個Playstation,他不會打擾你幾個星期。 – 2009-05-26 11:10:33

3

如果定界符被發現然後temp第一find呼叫後指向第一個分隔符有在你的while循環的問題。

在while循環結束時,您將beg設置爲temp的值。

現在beg也指向第一個分隔符。

當下一次調用find時,它將再次返回當前值beg,因爲它指向分隔符。

temp尚未從之前的值開始移動,因此您處於無限循環狀態。

1
vector<string> split(const string &str, const char &delim) 
{ 
    typedef string::const_iterator iter; 

    iter beg = str.begin(); 

    vector<string> tokens; 

    while(beg != str.end()) 
    { 
     iter temp = find(beg, str.end(), delim); 
     if(beg != str.end()) 
      tokens.push_back(string(beg, temp)); 
     if(temp != str.end()) 
      temp++; 
     beg = temp; 
    } 

    return tokens; 
} 
+0

或只是說,beg = temp + delim.size(); – xtofl 2009-05-26 07:37:30

0

調試代碼最簡單的方法,是打印所有的位置beg會。如果beg不增加那麼這就是你的問題。

0

除了beg需要增加分隔符的大小之外,還會丟失一個特殊情況:字符串中沒有分隔符的情況。

1

也許這一個:

std::vector<std::string> &mysplit(const std::string &s, char delim, std::vector<std::string> &elems) { 
    std::stringstream ss(s); 
    std::string item; 
    while(std::getline(ss, item, delim)) { 
     elems.push_back(item); 
    } 
    return elems; 
} 
4

我得愛Boost,因爲它提供了一個方便的解決方案,這其中還有:


std::vector<std::string> Split(const std::string &s, const std::string &d) 
{ 
     std::vector<std::string> v; 

     for (boost::split_iterator<std::string::iterator> i = boost::make_split_iterator(s, boost::first_finder(d, boost::is_iequal())); 
      i != boost::split_iterator<std::string::iterator>(); 
      ++i) { 
       v.push_back(boost::copy_range<std::string>(*i)); 
     } 

     return v; 
} 
1

你不必重新發明wheel,boost爲你提供了一個string splitting的功能。
示例代碼:

string stringtobesplit = "AA/BB-CC") 
vector<string> tokens; 

boost::split(tokens, stringtobesplit, boost::is_any_of("/-")); 
// tokens now holds 3 items: AA BB CC 
5

下面是一個使用整個字符串作爲分隔符另一個很好的和短期的基於加速版本:

std::vector<std::string> result; 
boost::iter_split(result, str, boost::first_finder(delim)); 

或者不區分大小寫:

std::vector<std::string> result; 
boost::iter_split(result, str, 
    boost::first_finder(delim, boost::is_iequal()));