【问题标题】:C++ incomplete output when splitting string拆分字符串时C ++不完整的输出
【发布时间】:2016-10-09 06:52:06
【问题描述】:

我试图从这样的字符串中提取某些数据:

2833ae7~2be;2833ae8~2272

我要做的是首先用冒号分割它,然后是每条记录,查找它是否包含2be,然后将包含它的记录分割为~2be,然后只给我~2be之前的值

我写了一些文章,这段代码可以做到,但问题是它没有给我完整的输出:

#include <string>
#include <sstream>
#include <vector>
#include <iostream>
using namespace std;

vector<string> split(string str,string sep){
    char* cstr=const_cast<char*>(str.c_str());
    char* current;
    vector<string> arr;
    current=strtok(cstr,sep.c_str());
    while(current!=NULL){
        arr.push_back(current);
        current=strtok(NULL,sep.c_str());
    }
    return arr;
}

int main(){
string items = "2833ae7~2be;2833ae8~2272";
vector<string> food = split(items, ";");
for(unsigned int i = 0; i < food.size(); i++)
{
    if(food[i].find("2be") != string::npos)
    {
        vector<string> arr = split(food[i],"~2be");


        cout << "Output ("<< i << ") = " << arr[0] << endl;

        }// end if

}// end for

    return 0;
}// end main

我得到的输出是:

Output <0> = 833a

什么时候应该:

Output <0> = 2833ae7

我做错了什么?

【问题讨论】:

  • 第一个问题是您在std::string 对象上使用了C 字符串函数。 c_str 中的 c 代表 constant。不应修改数据。来自this c_str reference:“写入通过 c_str() 访问的字符数组是未定义的行为。”而strtok 函数写入 到字符串。你必须做一个const_cast 应该表明你做了一些你不应该做的事情。
  • 您错误地使用了strtok。该函数的第二个参数是一个字符串,其中包含将用作标记的分隔符集。当您将 "~2be" 传递给函数时,它会尝试在第一个参数中查找任何这些字符。当第一个参数为"2833ae7" 时,它将在第一个2 处中断并返回一个空字符串。
  • current=strtok(cstr,sep.c_str()) -- 未定义的行为。 strtok 改变传递给它的数据,cstr 指向 const char *
  • 作为替代:std::vector&lt;char&gt; cstr(str.begin(), str.end()); cstr.push_back(0); 然后strtok(cstr.data(), sep.c_str())

标签: c++ string vector split


【解决方案1】:

正如其他人在 cmets 中提到的,修改从 std::string::c_str() 获得的字符数组是未定义的行为。 strtok()修改了它的参数来标记token,所以这里不能使用。

用单字符分隔符分割std::string 并不难。您可以这样做的一种方法是:

std::vector<std::string> split(const std::string &input, std::string::value_type delim)
{
    std::stringstream ss(input);
    std::vector<std::string> tokens;
    std::string token;
    while (std::getline(ss, token, delim))
    {
        tokens.push_back(token);
    }

    return tokens;
}

然后你可以像这样分割你的字符串:

std::vector<std::string> tokens = split("2833ae7~2be;2833ae8~2272", ';');

这将为您提供一个包含两个元素的向量:“2833ae7~2be”和“2833ae8~2272”。

现在对于第二部分,您不能使用相同的 split() 方法,因为它仅适用于单字符分隔符。但你可以这样做:

for (std::size_t index = 0; index < tokens.size(); ++index)
{
    if (tokens[index].find("2be") != std::string::npos)
    {
        std::string::size_type pos = tokens[index].find("~2be");

        std::cout << "Output (" << index << ") = " << tokens[index].substr(0, pos) << "\n";
    }
}

使用相同的想法,您还可以尝试重写 split() 方法以使其适用于字符串分隔符,而不仅仅是像我的版本那样的单字符分隔符。

【讨论】:

    猜你喜欢
    • 2019-06-05
    • 2018-10-27
    • 1970-01-01
    • 2017-02-26
    • 2010-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-15
    相关资源
    最近更新 更多