繁体   English   中英

分割字符串

[英]Splitting a string

我有这段代码来分割字符串。 由于某种原因,它只是坐在那里什么都不做。 我不确定是什么问题。 顺便说一句,这里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;
}

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

每行之后,放置一个printf()或cout staement,将更改的变量转储到标准输出中。 然后运行您的代码,并向其传递一组简单的参数:

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

然后,检查输出以查看为什么您的实现无法正常工作。 您可能不得不中断代码,因为如果它只是坐在那里,那么您可能已经使自己成为了这些新成立的无限循环之一。

授人以鱼,他会吃了一天,教人渔,他永远不会再挨饿。

或Terry Pratchett版本:

给男人一些火,他会一天是温暖的, 放火的人,他会热情为他的余生。

更新:

既然您说过您实际上已经完成了我的建议,那么这就是从中发现的内容。 显然,当您在while循环结束时将beg设置为temp时,它指向的是空间。 这是通过在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. :

这是另一个不错的简短的基于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()));

我必须爱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;
}

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

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

现在, beg也指向第一个定界符。

当下一次调用find ,它将返回beg的当前值,因为它确实指向定界符。

temp尚未从其先前的值继续前进,因此您处于无限循环中。

find()将返回下一个标记的位置X。 然后,将其分配给beg并进入下一个迭代时,它将在位置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),并且多个delims不会导致清空令牌。

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

也许这一个:

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

您不必重新发明轮子,boost为您提供了字符串拆分功能。
示例代码:

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

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

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

除了需要增加定界符大小的beg be外,还缺少一种特殊情况:字符串中没有定界符的情况。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM