2009-05-26 205 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()));