【问题标题】:istream operator >> not recognising '\n' characteristream 运算符 >> 不识别 '\n' 字符
【发布时间】:2015-02-16 15:20:38
【问题描述】:

我基本上是在读取.txt 文件并存储值。

例如:

Student- Mark
Tennis

它将Mark作为studentName存储到内存中。

现在...如果只是

Student-
Tennis

然后它会正常工作并产生错误。

但是,如果文件看起来像这样

Student-(space)(nothing here)
Tennis

它将TennisstudentName 的形式存储到内存中,但实际上它不应该存储任何内容并产生错误。我使用'\n' 字符来确定- 字符之后是否有任何内容。这是我的代码...

istream& operator>> (istream& is, Student& student)
{   
    is.get(buffer,200,'-');
    is.get(ch);
    if(is.peek() == '\n')
    {
        cout << "Nothing there" << endl;
    }
    is >> ws;
    is.getline(student.studentName, 75);
}

我认为这是因为is.peek() 正在识别空白,但是如果我尝试使用is &gt;&gt; ws 删除空白,它会删除'\n' 字符并仍将Tennis 存储为studentName

如果有人能帮我解决这个问题,那真的意义重大。

【问题讨论】:

  • 你的 is.peek() == \n.....如果这是真的,那么你应该从函数中返回。
  • 使用 find_first_of() 函数查找第一个空格,以便您识别应该删除哪些空格。
  • 考虑回车可能应该是\n\r
  • 由于只想读取一行,所以使用std::getline读取该行,然后解析。
  • @SamThers 有,但是 C++ 字符串更安全,可以让您免于管理自己的内存的负担。当按预期使用时,它们还可以防止堆栈粉碎攻击。我强烈建议您不要使用 C 风格的字符串。没有时间像现在这样做出更好的改变。 (我还要指出,比起有人说“我宁愿使用错误的工具来完成这项工作。”这会导致不必要的复杂和错误的答案。)

标签: c++ char ifstream istream peek


【解决方案1】:

如果你想忽略空格但 '\n' 你不能轻易使用std::ws:它会跳过所有空格,除了' ' 字符'\n'(换行符)、'\t'(制表符)和@​​987654326@(回车符)被认为是空格(我认为实际上还有更多)。您可以重新定义空白对您的流的含义(通过将流的 std::locale 替换为自定义的 std::ctype&lt;char&gt; 方面,这改变了空白的含义)但这可能更高级一些(到目前为止据我所知,大约有少数人可以立即做到这一点;询问它,如果我注意到它,我会回答这个问题,不过......)。一种更简单的方法是使用std::getline() 读取行尾并查看其中的内容。

另一种选择是创建您自己的操纵器,比如说skipspace,并在检查换行符之前使用它:

std::istream& skipspace(std::istream& in) {
    std::istreambuf_iterator<char> it(in), end;
    std::find_if(it, end, [](char c){ return c != ' '; });
    return in;
}
// ...
if ((in >> skipspace).peek() != '\n') {
    // ....
}

【讨论】:

    【解决方案2】:

    你不需要偷看字符。我会使用std::getline() 并让它为您处理换行符,然后使用std::istringstream 进行解析:

    std::istream& operator>> (std::istream& is, Student& student)
    {   
        std::string line;
        if (!std::getline(is, line))
        {
            std::cout << "Can't read student name" << std::endl;
            return is;
        }
    
        std::istringstream iss(line);
        std::string ignore;
        std::getline(iss, ignore, '-');
        iss >> std::ws;
        iss.getline(student.studentName, 75);
    
        /*
        read and store className if needed ... 
    
        if (!std::getline(is, line))
        {
            std::cout << "Can't read class name" << std::endl;
            return is;
        }
    
        std::istringstream iss2(line);
        iss2.getline(student.className, ...);
        */
    
        return is;
    }
    

    或者,如果您可以将Student::studentName 更改为std::string 而不是char[]

    std::istream& operator>> (std::istream& is, Student& student)
    {   
        std::string line;
        if (!std::getline(is, line))
        {
            std::cout << "Can't read student name" << std::endl;
            return is;
        }
    
        std::istringstream iss(line);
        std::string ignore;
        std::getline(iss, ignore, '-');
        iss >> std::ws >> student.studentName;
    
        /*
        read and store className if needed ... 
    
        if (!std::getline(is, student.className))
        {
            std::cout << "Can't read class name" << std::endl;
            return is;
        }
        */
    
        return is;
    }
    

    【讨论】:

    • 如果我想使用c style arrays怎么办?我更喜欢使用c style arrays,它只是在is.peek()==ws 和空格之后的所有内容都是空白时出现问题
    • 我不建议使用 C 样式数组进行读取/解析。 STL 的解析功能更喜欢std::string。但是,正如您在我的第一个示例中看到的那样,解析的结果至少存储在最终的 C 样式数组中。
    猜你喜欢
    • 2015-01-15
    • 1970-01-01
    • 2021-12-16
    • 2015-06-27
    • 2017-05-31
    • 2015-06-13
    • 2015-11-08
    • 2013-10-10
    • 2015-07-25
    相关资源
    最近更新 更多