std::getline() 不会忽略空格

Posted

技术标签:

【中文标题】std::getline() 不会忽略空格【英文标题】:std::getline() does not ignore white space 【发布时间】:2021-12-27 04:48:53 【问题描述】:

我是 C++ 新手,在阻止 getline 读取文本文件末尾的换行符时遇到了一些问题。我尝试使用换行符截断它,然后用','传递给定界符,但它不起作用。您能否帮助我了解发生了什么以及为什么我无法实现我想要做的事情?

我已经编辑了这篇文章以更正 getline() 的错误,而不是可用的。但是我不知道如何传输这个 getline() 字符串以防止使用'\n' 字符

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
static int Ncol = 5;
int main()

    int ctr=0,Nrow;
    std::string line,line1;
    std::ifstream myFile1;

    Nrow = 4;
    std::cout.precision(15);
    std::fixed;

    double* input = new double[Nrow*Ncol];
    double* ftrue = new double[Nrow];

    myFile1.open("./Data_codelink_test/test.txt");
    
    while(ctr<Nrow)
       
        std::getline(myFile1,line1,','); // This gives me line1 with the new line character
        std::cout<<"Read "<<line1<<std::endl;
        input[ctr] = std::stold(line1);
        std::cout<<"Stored "<<input[ctr]<<std::endl;
        ctr++;  
    
    myFile1.close();

我的 test.txt 是这样的

1,2,3,4,5
1,2,3,4,5
1,2,3,4,5
1,2,3,4,5

我想要一个大小为 20 的向量以这种方式存储值

1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5

【问题讨论】:

getline 失败时,它返回false。这段代码并没有对此进行检查,因此它会继续其愉快的方式。 How to debug small programs @RemyLebeau 感谢您指出这一点。但即使我在 while 循环中将 getline() 限制为适当的数量,它也不能解决我的主要问题。我看不出如何防止 std::getline(myFile1,line,',') 在每行末尾获取 '\n' 值。对此的任何建议将不胜感激。谢谢 @readysetcode "它不能解决我的主要问题" - 究竟是什么?你没有解释清楚。 “我看不到如何防止 std::getline(myFile1,line,',') 在每行末尾获取 '\n' 值” - 这正是确实如此。它仅在读取 specified 分隔符时停止。如果它对您不起作用,那么还有其他问题。 “它不起作用”不是一个有用的描述。为什么你认为它不起作用?请详细说明。 @readysetcode 现在您已将代码更改为使用 1 getline() 而不是 2。这从根本上改变了代码的行为(并使我的答案无效)。以前的代码实际上在解决您的问题方面做得更好,这个新代码引入了您所询问的问题。请还原代码,然后解释为什么原始代码不适合您。 【参考方案1】:

我看到的唯一问题(更新:在您编辑之前使用 原始 代码)是您调用 std::getline('\n') 的次数(25 次)比文件中的实际行数(4)多。到达 EOF 时,您不会终止循环。请改用此循环条件:

while ((ctr < (Nrow*Ncol)) && std::getline(myFile1, line))

Nrow*Ncol 项目已存储在数组中或std::getline() 未能读取文件中的下一行时,这将结束循环。

话虽如此,请考虑使用std::vector 而不是new[]。让vector随着读取成功的每一行动态增长,例如:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>

int main()

    std::ifstream myFile1("./Data_codelink_test/test.txt");

    std::vector<double> input;
    std::string str;

    std::cout << std::fixed << std::setprecision(15);

    while (std::getline(myFile1, str))
    
        std::istringstream iss(str);
        std::getline(iss, str, ',');
        std::cout << "Read " << str << std::endl;
        input.push_back(std::stold(str));
        std::cout << "Stored " << input.back() << std::endl; 
    
    myFile1.close();

    ...


更新:使用您提供的任一代码 sn-p 都无法达到您想要的结果。在原始代码中,您可以很好地阅读这些行,但随后您只提取了每行中的第一个数字。在您编辑的代码中,您读取的是逗号分隔的数字,根本不考虑行,因此您会定期读取中间有换行符的字符串。

std::getline() 一次只能处理 1 个分隔符。因此,要解析 std::getline() 所拥有的数据类型,您需要 2 个循环 - 一个循环读取每一行,一个循环拆分每一行,例如:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <sstream>

static int Ncol = 5;

int main()

    std::ifstream myFile1("./Data_codelink_test/test.txt");

    int ctr = 0, Nrow = 4, maxElems = Nrow*Ncol;
    std::string str;

    double* input = new double[maxElems];

    std::cout << std::fixed << std::setprecision(15);

    while ((ctr < maxElems) && std::getline(myFile1, str))
    
        std::istringstream iss(str);
        while ((ctr < maxElems) && std::getline(iss, str, ',')) 
            std::cout << "Read " << str << std::endl;
            input[ctr] = std::stold(str);
            std::cout << "Stored " << input[ctr] << std::endl;
            ++ctr;
        
    
    myFile1.close();

    ...

或者,使用std::vector:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>

int main()

    std::ifstream myFile1("./Data_codelink_test/test.txt");

    std::vector<double> input;
    std::string str;

    std::cout << std::fixed << std::setprecision(15);

    while (std::getline(myFile1, str))
    
        std::istringstream iss(str);
        while (std::getline(iss, str, ',')) 
            std::cout << "Read " << str << std::endl;
            input.push_back(std::stold(str));
            std::cout << "Stored " << input.back() << std::endl;
        
    
    myFile1.close();

    ...

【讨论】:

这个程序的目的是将文本文件的每个整数存储到一个向量元素中。但是我没有看到这个程序存储每个值。从我使用此代码运行的内容来看,它只存储第一个值。我需要向量输入来顺序存储 20 个数字,而这段代码不这样做。如果我遗漏了什么,你能详细说明吗? (我将 std::precision(15) 固定为 std::cout.precision(15) 以便它不会抛出错误) @readysetcode 您的代码不起作用,因为您没有正确处理文件数据。我已经更新了我的答案。【参考方案2】:

std::getline 只接受单个字符作为分隔符:

Can I use 2 or more delimiters in C++ function getline?

使用两个循环读取数据更清晰:

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
static int Ncol = 5;
int main()

    int column=0,Nrow;
    std::string line,field;
    std::ifstream myFile1;

    Nrow = 5;
    std::cout.precision(15);
    std::fixed;

    double* input = new double[Nrow*Ncol];
    double* ftrue = new double[Nrow];

    myFile1.open("./Data_codelink_test/test.txt");

    int row = 0;
    while (std::getline(myFile1, line))
    
        std::stringstream stream(line);
        int column = 0;
        while(column < Ncol)
           
            std::getline(stream,field,','); // This gives me line1 with the new line character
            std::cout<<"Read "<<field<<std::endl;
            input[row *  Ncol + column] = std::stold(field);
            std::cout<<"Stored "<<input[row *  Ncol + column]<<std::endl;
            column++;  
        
        row++;
    
    myFile1.close();

结果是:

【讨论】:

以上是关于std::getline() 不会忽略空格的主要内容,如果未能解决你的问题,请参考以下文章

std::getline() 返回

为啥我可以在不使用 std::getline 的情况下调用 getline?

std::getline 在遇到 eof 时抛出

为啥 std::getline() 在格式化提取后跳过输入?

为啥 std::getline() 在格式化提取后跳过输入?

为啥 std::getline() 在格式化提取后跳过输入?