【问题标题】:How to implement split function to split words from a line?如何实现拆分功能以从一行中拆分单词?
【发布时间】:2020-07-27 22:04:24
【问题描述】:

我想实现一个函数,它将string 作为输入行(通过getline())并在向量中分隔(拆分)单词。我试过这个:

vector<string> split(const string &s)
{
    vector<string> ret;
    int j = 0, i = 0; // j=="start word boundary", i=="end word boundary"
    while (i != s.size())
    {
        //get words
        while (i != s.size() && !isspace(s[i]))
        {
            i++;
        }
        //at least one word found (so the 'i' index is not at the beginning of string)
        if (!i)
        {
            ret.push_back(s.substr(j, i - j));
        }
        //now look for blanks
        j = i;
        //ignore blanks
        while (j != s.size() && isspace(s[j]))
        {
            j++;
        }
        //get position for next words back
        i = j;
    }
    return ret;
}

然后尝试查看结果:

int main()
{
    string tmp;
    while (getline(cin, tmp))
    {
        vector<string> vec = split(tmp);
        for (string s : vec)
        {
            cout << s << endl;
        }
    }
}

但是什么都看不到。为什么?

【问题讨论】:

  • A std::istringstream 对这项任务非常有用。只是说。关于你的代码,split2 != split,所以从那开始。
  • 我建议阅读函数 std::string::first_ofstd::string::first_not_of". For example, you can define whitespace characters in a string and find positions that are not whitespace using std::string::first_not_of"。
  • @ThomasMatthews 谢谢,我会查的。这只是通过索引和substr 实现它的一种执行方式,没有迭代器。

标签: c++ algorithm split


【解决方案1】:

这里有错别字:

if (!i)
{
   ret.push_back(s.substr(j, i - j));
}

如果结束索引是0,您只会添加子字符串,但这意味着您永远不会向向量添加子字符串。

相反,如果结束索引不是 0,则需要添加子字符串:

if (i)   // if (i != 0)
{
   ret.push_back(s.substr(j, i - j));
}

这是demo

【讨论】:

  • 谢谢,我想确定,'i' 不是 0,但这与我写的相反。非常感谢
  • @milanHrabos 你可以写if (i != 0)更明确
【解决方案2】:

试试类似的方法:

vector<string> split(const string &s)
{
    vector<string> ret;
    size_t size = s.size(), start = 0, end;
    do
    {
        // skip leading whitespace
        while (start < size && isspace(s[start])){
            ++start;
        }
        if (start == size) break;

        //at least one word found
       
        // find the next whitespace, or end-of-string, whichever comes first
        end = start + 1;
        while (end < size && !isspace(s[end])){
            ++end;
        }

        //get word
        ret.push_back(s.substr(start, end - start));
        
        start = end;
    }
    while (start < size);

    return ret;
}

然后可以使用std::string::find_first(_not)_of() 稍微简化一下,例如:

static const char *ws = " \t";

vector<string> split(const string &s)
{
    vector<string> ret;

    size_t size = s.size(), start = 0, end;
    while ((start = s.find_first_not_of(ws, end)) != string::npos)
    {
        if ((end = s.find_first_of(ws, start+1)) == string::npos){
            ret.push_back(s.substr(start));
            break;
        }
        ret.push_back(s.substr(start, end-start));
        start = end;
    }

    return ret;
}

不过,将std::istringstreamoperator&gt;&gt; 一起使用会更简单:

...
#include <sstream>

vector<string> split(const string &s)
{
    vector<string> ret;
    istringstream iss(s);
    string word;
    while (iss >> word){
        ret.push_back(word);
    }
    return ret;
}

或者,而不是使用手动循环:

...
#include <sstream>
#include <iterator>
#include <algorithm>

vector<string> split(const string &s)
{
    vector<string> ret;
    istringstream iss(s);
    std::copy(istream_iterator<string>(iss), istream_iterator<string>(), back_inserter(ret));
    return ret;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-18
    • 2021-10-30
    • 2013-02-08
    • 2020-05-18
    相关资源
    最近更新 更多