【问题标题】:Bug with Iterating over a string c++迭代字符串c ++的错误
【发布时间】:2018-05-02 08:49:04
【问题描述】:

所以我有一个名为 split_alpha() 的函数,它接收一个 std::string 并将字符串拆分为单词,使用任何非字母数字字符作为分隔符。它还将单词映射到它们的小写版本。

vector<string> split_alpha(string to_split) {

    vector<string> results;
    string::iterator start = to_split.begin();
    string::iterator it = start;
    ++it;
    //get rid of any non-alphaneumeric chars at the front of the string
    while (!isalnum(*start)) {
        ++start;
        ++it;
    }

    while (it != to_split.end()) { 
        if (!isalnum(*it)) {
            string to_add = string(start, it);
            lower_alpha(to_add);
            results.push_back(to_add);
            ++it;
            if (it == to_split.end()) { break; }
            while (!isalnum(*it)) {
                ++it;
                if (it == to_split.end()) { break; }
            }
            start = it;
            ++it;
        }
        else {
            ++it;
            if (it == to_split.end()) { break; }
        }
    }

    //adds the last word
    string to_add = string(start, it);
    lower_alpha(to_add);
    results.push_back(to_add);

    return results;
}

该函数在 99% 的情况下都能正常工作,但是当我给它输入字符串“Sending query: “SELECT * FROM users””(不包括整个字符串的引号)时,它会做一些非常奇怪的事情。它本质上进入了一个无限循环(在那个while循环内)并且永远不会找到字符串的结尾。相反,它会不断从某个地方读取随机字符/字符串??在最终出现段错误之前,我的向量最终大小约为 200。有谁知道这可能是什么原因造成的?我尝试打印出字符串,看起来非常好。再一次,该代码适用于我尝试过的所有其他字符串。 谢谢!!

【问题讨论】:

  • 为澄清起见,过去 2 天我一直在尝试使用我的 IDE (xcode) 调试这个问题,我已经经历了 100 次(这就是我发现它正在读取随机字符而不是到达字符串的末尾),这也是我发现我的代码适用于所有其他字符串的方式。我还打印了我的代码迭代的每个字符串,它们看起来都很正常。我不理解我会在不尝试任何调试的情况下发布此内容的假设。
  • 每当你增加一个迭代器或一个指针时,你必须在使用它之前检查增加的结果是否有效。
  • while 循环不是这样做的吗?它在执行任何代码之前检查迭代器是否不在字符串的末尾(至少我是这么认为的)
  • 您在循环中多次递增迭代器,而不检查结果是否有效。
  • 正如@NeilButterworth 所说,小心从字符串的末端走开。例如,while (!isalnum(*it)) { ++it; } 不检查字符串的结尾。

标签: c++ string loops split


【解决方案1】:

while 循环不是这样做的吗?

是的,但是您可以在 while 循环检查之前触发多个 ++it,并且在任何一种情况下,迭代器都可能已经在字符串。您尝试的其他字符串很可能不会导致失败,因为它们都以字母数字字符结尾。

颠倒++it和检查的顺序:

if (it == to_split.end()) { break; }
++it;

解释:下面的断言将失败,因为迭代器将不再指向字符串的末尾(而是进一步指向一个字符):

if (it == to_split.end())
{
    ++it;
    assert(it == to_split.end());
}

【讨论】:

    【解决方案2】:

    由于已经指出了函数中错误的根源,我可以建议您使用正则表达式的分词方法略有不同:

    #include <iostream>
    #include <regex>
    #include <vector>
    #include <string>
    #include <cctype>
    
    std::vector<std::string> split_alpha(std::string str)
    {
        std::regex RE{ "([a-zA-Z0-9]+)" }; // isalnum equivalent
        std::vector<std::string> result;
    
        // find every word
        for (std::smatch matches; std::regex_search(str, matches, RE); str = matches.suffix())
        {
            //push word to the vector
            result.push_back(matches[1].str());
    
            //transform to lower
            for (char &c : result[result.size() - 1])
                c = std::tolower(c);
        }
    
        return result;
    }
    
    int main()
    {
        // test the function
        for (auto &word : split_alpha("Sending query: “SELECT * FROM users”"))
            std::cout << word << std::endl;
    
        return 0;
    }
    

    结果:

    sending
    query
    select
    from
    users
    

    【讨论】:

      猜你喜欢
      • 2011-07-22
      • 2023-04-10
      • 2014-12-09
      • 2023-03-13
      • 2017-11-25
      • 1970-01-01
      • 2017-12-15
      • 1970-01-01
      • 2015-07-04
      相关资源
      最近更新 更多