迭代字符串 c++ 的错误

Bug with Iterating over a string c++

本文关键字:错误 c++ 字符串 迭代      更新时间:2023-10-16

所以我有一个名为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% 的时间内工作正常,但是当我给它字符串"发送查询:"SELECT * FROM 用户"(不包括整个字符串周围的引号(时,它做了一些非常奇怪的事情。它本质上进入一个无限循环(在该 while 循环中(,并且永远不会找到字符串的结尾。相反,它不断从某个地方读取随机字符/字符串??我的向量最终的大小约为 200,然后最终出现段错误。有谁知道是什么原因造成的?我尝试打印出字符串,看起来很好。再一次,代码适用于我尝试过的所有其他字符串。谢谢!!

while 循环不是这样做的吗?

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

反转 ++it 和检查的顺序:

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

说明:以下断言将失败,因为迭代器将不再指向字符串的末尾(而是指向一个字符(:

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

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

#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