【问题标题】:Split function throws error [closed]拆分函数引发错误[关闭]
【发布时间】:2013-02-01 21:36:17
【问题描述】:

我正在尝试创建一个函数来将字符串“Split At Spaces”拆分为一个包含“Split”“At”“Spaces”的向量。到目前为止,这是我得到的代码。

#include <iostream>
#include <utility>
#include <algorithm>

using namespace std;

std::vector<std::string> split(std::string * s, char * tosplit) 
{
    size_t i = 0;
    int count = 0;
    size_t contain;
    std::vector<std::string> split;

    std::cout << "Start" << std::endl;
    std::cout << *s << std::endl;
    std::cout << *tosplit << std::endl;

    while((contain = s->find(*tosplit,i)) != std::string::npos)
    {
        count++;
        i = contain + 1;
    }

    std::cout << "Contains " << count << std::endl;

    if (count == 0)
    {
        std::cout << "Equals 0" << std::endl;
        split = std::vector<std::string>(1);
        split.at(0) = s->c_str();
        return split;
    }

    split = std::vector<std::string>(count + 1);
    split.begin();

    int lasti;
    i = s->find_first_of(*tosplit);
    split.at(0) = s->substr(0, i);
    lasti = i;
    int runs = 1;

    while (runs <= count) 
    {
        i = s->find(*tosplit, lasti + 1);
        std::cout << i << " " << lasti << std::endl;
        split.at(runs) = s->substr(lasti, --i);
        runs++;
        lasti = i;
    }

    split.at(runs) = s->substr(lasti, s->size());

    std::cout << "done, result is" << std::endl;
    i = 0;
    while (i < split.capacity()) 
    {
        std::cout << split.at(i) << std::endl;
        i++;
    }

    return split;
}

它会抛出一个 out_of_range 异常。您可以提供的任何帮助将不胜感激。这就像我在函数中使用指针的第一部分,所以我有点猜测。
谢谢!

请不要建议使用 x 或 y 方法,我想自己写,因为我是为了体验。

【问题讨论】:

  • 你为什么用std::string的指针?
  • 您也不需要将 char 作为指针传递。
  • 使用调试器时,哪一行抛出异常?
  • std::vector::capacity 不返回向量的大小
  • 请查看std::string 了解如何使用begin 方法。在您的帖子中,您不妨将其删除。

标签: c++ string split


【解决方案1】:

以下是我发现的一些问题:

  1. 在检查 NULL 指针之前取消引用 s
  2. 在检查 NULL 之前取消引用 tosplit
  3. 而不是计算字符串的数量,然后拆分 字符串(需要 2 次搜索),在搜索时计入。
  4. 位置i = contain + 1在您通过时可能超出范围 while 循环中的表达式。
  5. 尝试使用方法std::vector::push_back而不是分配 在一个特定的(可能是未分配的)位置。
  6. 语句return split 返回字符串数组的副本。 您真的要返回大型数据结构吗?
  7. 语句split.begin()将迭代器返回到开头 向量的;你不使用的。
  8. 使用split.size() 而不是split.capacity。他们是两个不同的 概念。

【讨论】:

    【解决方案2】:

    这实际上很容易做到,例如std::istringstreamstd::copy,以及来自 standard iterator library 的一些帮助。

    想要查看工作代码的朋友,可以找到here

    对于链接中的代码,整个程序是18行,其中实际拆分为3行但那是因为我将它拆分为使其更具可读性(实际上是单个函数调用)。


    对于更通用的解决方案,如果 C++11 regular expressions 可用(或Boost regex,或其他一些可用的正则表达式库),则可以使用。

    【讨论】:

    • "请不要建议使用 x 或 y 方法,我想自己写,因为我正在这样做。"
    • 我打算发布常见问题条目,直到看到帖子的最后一行。尽管如此,它们仍可用于激发灵感。
    • @Rapptz 哎呀,第一次没有看到,更新了我的答案以删除代码。
    • 我认为没有必要在链接上添加剧透 ;)
    • @chris 可能不会,但我以前从未使用过扰流板。 :)
    【解决方案3】:

    单分隔符:

    您为此编写了太多代码。您可以在几行内完成。你变得非常过于复杂了。并且没有理由真正为此使用指针做任何事情。

    vector<string> Split(string s, char delim)
    {
        vector<string> strings;
        for(istringstream ss(s); getline(ss, s, delim); strings.push_back(move(s)));
        return strings;
    }
    

    多个分隔符:

    使用多个分隔符的解决方案更复杂。您不能再利用getline,这意味着您基本上是在自己编写getline 的部分功能。但是,它仍然可以很短。

    vector<string> Split(const string& s, const char* delims)
    {
        vector<string> strings;
    
        for(string::size_type start = 0, end; end != string::npos && start < s.size(); start = end+1)
        {
            end = s.find_first_of(delims, start);
            strings.push_back(s.substr(start, end-start));
        }
    
        return strings;
    }
    

    当分隔符彼此相邻时,这将添加空白字符串。如果这不是相邻分隔符所期望的行为,则可以通过用if(start != end) 保护push_back 来轻松避免这种情况。

    结论:

    当您开始编写类似这样的低级算法时,请先对其进行广义的伪代码,然后在编写任何代码之前检查 C++ 标准库可以提供哪些内容来删减您的部分或全部工作。您最终会得到更小、更不容易出错且更易于理解的代码。例如,没有人希望看到 find_first_of 的手动实现。阅读find_first_of这个词会更清楚。很清楚该函数要做什么,并且它没有错误(希望如此)。

    【讨论】:

    • 耶稣我完全错过了。有什么办法可以分割两个分隔符吗? (例如 + 和一个空格
    • @Tips48 我编辑了我的答案以包含多个 delims 的解决方案
    • 使用您的代码,我收到此错误:错误 7 错误 LNK2019:未解析的外部符号 "class std::vector,class std::allocator >,std::allocator,std::allocator > > __cdecl split(std:: basic_string,class std::allocator,char)" 我忽略了其余的错误,但如果它很重要,请告诉我。此外,您是否有机会解释 const 和 & 在 string 和 char 变量中的用途?谢谢!
    【解决方案4】:

    不要尝试为您的向量预先分配空间,只需使用 push_back 来附加您找到的部分。

    【讨论】:

    • 不知道你能做到,谢谢
    【解决方案5】:

    对不起,我不禁认为您的功能过于复杂。如果您想自己编写逻辑代码用于学习而不是使用一些预先打包的功能,那很好,但这并不意味着您不应该保持逻辑简单

    我相信你的算法应该更像这个:

    // Note that the delimiter can be a string as well, not just a char
    vector<string> split(string const& s, string const& delimiter)
    {
        vector<string> result;
    
        string::size_type startPos = 0;
        string::size_typepos = s.find(delimiter);
        while (pos != string::npos)
        {
            // Extract token and save it...
            string token = s.substr(startPos, pos - startPos);
            result.push_back(token);
    
            // Step to next token...
            startPos = pos + 1;
            pos = s.find(delimiter, pos + 1);
        }
    
        // Parse last token (in case the string is not terminated
        // by the delimiter).
        if (startPos < s.length())
        {
            string lastToken = s.substr(startPos);
            result.push_back(lastToken);
        }
    
        return result;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多