C++ STL分割逗号分隔的字符串

3
我知道有几个相关的问题,例如解析逗号分隔的std :: string。然而,我创建了一段代码,符合我的特定需求-将从文件中读取的字符串在逗号处拆分并剥离任何空格。稍后,我想将这些子字符串转换为double并存储在std :: vector中。不是所有操作都显示。这是我提供的代码。
include "stdafx.h"
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>

int main()
{
    std::string str1 = "  0.2345,  7.9  \n", str2;
    str1.erase(remove_if(str1.begin(), str1.end(), isspace), str1.end()); //remove whitespaces
    std::string::size_type pos_begin = { 0 }, pos_end = { 0 };


    while (str1.find_first_of(",", pos_end) != std::string::npos)
    {
        pos_end = str1.find_first_of(",", pos_begin);
        str2 = str1.substr(pos_begin, pos_end- pos_begin);
        std::cout << str2 << std::endl;
        pos_begin = pos_end+1;
    }

}

输出:

0.2345
7.9

所以程序是这样的。while循环搜索,的出现,pos_end将存储第一个,的出现,str2将成为子字符串,pos_begin将移动到pos_end后一位。第一次迭代将正常运行。

在下一次迭代中,pos_end将是非常大的值,我不确定pos_end - pos_begin会是什么。同样的情况也适用于pos_begin(尽管它将不被使用)。要进行一些检查,例如

if (pos_end == std::string::npos)
        pos_end = str1.length();

还有进一步改进的余地吗?

这个程序确实可以运行 (g++ -Wall -Wextra prog.cpp -o prog -std=c++11)。这种做法正确吗?


1
使用适当的分隔符,std::istringstreamstd::getline()怎么样? - user9212993
1
“它能用于从文件中读取可变长度字符串吗?”将其放入一个函数中并找出答案。 - user4581301
返回一个子字符串 [pos,pos+count)。如果请求的子字符串扩展到超出字符串的末尾,或者 count == npos,则返回的子字符串为 [pos,size())。 因此,如果pos_end很大,这不是问题。 - super
1
你可能想看一下如何在C++中读取和解析CSV文件?的答案,然后跳过从文件读取行到字符串的步骤。 - Bo Persson
不清楚为什么会被踩。但我看到有一个与主题无关的关闭投票。问题:看起来目标是 vector <double> v1。你打算如何处理空令牌?例如:", 0.2345, 7.9 \n" - user4581301
显示剩余11条评论
2个回答

2

我在C++20中使用了ranges库,并且实现如下:

#include <iostream>
#include <ranges>
#include <algorithm>
#include <vector>
    
auto join_character_in_each_subranges = [](auto &&rng) { 
      return std::string(&*rng.begin(), std::ranges::distance(rng)); };

auto trimming = std::ranges::views::filter([](auto character){ 
      return !std::isspace(character);});

int main()
{
    std::string myline = "  0.2345,  7.9  ";

    std::vector<double> line_list;

    for (std::string&& words : myline 
            | std::ranges::views::split(',') 
            | std::ranges::views::transform(join_character_in_each_subranges))
    {
        auto words_trimming = words | trimming;
        std::string clean_number;
        std::ranges::for_each(words_trimming, 
             [&](auto character){ clean_number += character;});

        line_list.push_back(atof(clean_number.c_str()));
    }
}

首先,迭代myline句子并在分隔符上将视图拆分成子范围。

 myline | std::ranges::views::split(',') 

获取每个子范围,将每个字符附加到彼此并使用transform函数查看std::string中的内容。

std::transform将给定的函数应用于一个范围,并将结果存储在另一个范围中。

 std::ranges::views::transform(join_character_in_each_subranges)

另外,从视图范围中删除任何前缀和后缀。
auto words_trimming = words | trimming;

将视图范围转换为std::string
std::ranges::for_each(words_trimming, [&](auto character){ clean_number += character;});

最后,将每个clean_number转换为doublepush_back到列表中。
line_list.push_back(atof(clean_words.c_str()));

1
你的抹去成语可能无法在更现代的编译器上编译,因为isspace被重载了。在某些情况下,使用范围循环删除空格可能更有效。 所讨论的算法取决于您是否需要存储令牌和在行中校正“语法”错误并存储或不存储空令牌。
#include<iostream>
#include<string>
#include<list>
#include<algorithm>

typedef std::list<std::string> StrList;



void tokenize(const std::string& in, const std::string& delims, StrList& tokens)
{
    tokens.clear();

    std::string::size_type pos_begin  , pos_end  = 0;
    std::string input = in;

    input.erase(std::remove_if(input.begin(), 
                              input.end(),
                              [](auto x){return std::isspace(x);}),input.end());

    while ((pos_begin = input.find_first_not_of(delims,pos_end)) != std::string::npos)
    {
        pos_end = input.find_first_of(delims,pos_begin);
        if (pos_end == std::string::npos) pos_end = input.length();

        tokens.push_back( input.substr(pos_begin,pos_end-pos_begin) );
    }
}

int main()
{
  std::string str = ",\t,  0.2345,, , ,  7.9  \n";
  StrList vtrToken;

  tokenize( str, "," , vtrToken);

    int i = 1;
  for (auto &s : vtrToken)
      std::cout << i++ << ".) " << s << std::endl;

   return 0;
}

输出:

1.) 0.2345
2.) 7.9

这个变量会删除所有的空令牌。在你的情境中是否正确未知,因此没有正确答案。如果你需要检查字符串是否正确,或者需要用默认值替换空令牌,则需要添加额外的检查。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接