分裂一个字符串

时间:2009-05-26 07:04:29

标签: c++

我有这个代码来分割一个字符串。出于某种原因,它只是坐在那里什么都不做。我不确定问题是什么。顺便说一下,delim = ' '在这里。

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;
}

10 个答案:

答案 0 :(得分:6)

可以为你调试它,我想但从长远来看这对你没有帮助。这是你做的。

在每一行之后,将printf()或cout staement转换为标准输出。然后运行代码,将一组简单的参数传递给它:

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

然后,检查输出以查看您的实现无法正常工作的原因。你可能不得不打破代码,因为如果它只是坐在那里,你可能会得到一个新的无限循环。

  

给一个人一条鱼,他会吃一天,教一个人 鱼,他永远不会再饿了。

或Terry Pratchett版本:

  

给一个男人一些火,他会温暖一天,在火上放一个男人,他将在余生中保持温暖。

<强>更新

既然你已经表明你已经完成了我的建议,那么这就是从中发现的东西。很明显,当您在beg循环结束时将temp设置为while时,它指向的是空格。通过在beg循环顶部打印while字符串来发现这一点 - 在提取第一个单词后它永远不会改变。

然后,当你执行下一个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. :

答案 1 :(得分:5)

这是另一个很好的简短的基于Boost的版本,它使用整个字符串作为分隔符:

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()));

答案 2 :(得分: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;
}

答案 3 :(得分:3)

你的while循环中存在一个问题,即如果找到分隔符,则temp将在第一次find调用后指向第一个分隔符。

在while循环结束时,您将beg设置为temp的值。

现在beg也指向第一个分隔符。

下次调用find时,它会再次返回当前值beg,因为它指向分隔符。

temp尚未从之前的值移开,因此您处于无限循环中。

答案 4 :(得分: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)并且多个delim不会导致空标记。

答案 5 :(得分: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;
}

答案 6 :(得分: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;
}

答案 7 :(得分:1)

您不必重新发明轮子,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

答案 8 :(得分:0)

调试此代码的最简单方法是打印beg所有的位置。如果beg没有增加,那就是你的问题。

答案 9 :(得分:0)

除了beg需要使用分隔符的大小递增外,还会遗漏一个特殊情况:字符串中没有分隔符的情况。