使用c++流读取换行符

Read newline using stream C++

本文关键字:换行符 读取 c++ 使用      更新时间:2023-10-16

如何使用c++>>操作符读取新行?

ifstream input("doc.txt".c_str());
vector<string> contents;
while (input >> word) {
    contents.push_back(word);
}

对于文件:

hello 
world
C++ is the best tool

应该返回

hello
n
world
n
C++
is
the
best
tool
p/S:这是一个大问题的简化版。我解析文件的方式导致了这个问题。

您可以自己使用std::getline, push_back"n",正如jaggedSpire所提到的:

std::ifstream input("doc.txt");
std::vector<std::string> contents;
for (std::string line; std::getline(input, line);) {
    std::istringstream str(line);
    for (std::string word; str >> word;) {
        contents.push_back(word);
    }
    contents.push_back("n");
}

如果你正在寻找具体使用operator>>和你不技术上需要使用字符串具体,你可以简单地做一个自定义类的行为,你想当它从istream读取。它甚至可以(主要)作为字符串的包装器,在读取初始空白时具有自定义行为。

class StringAndNewline{
    std::string str_;
    friend std::istream& operator>>(std::istream& in, StringAndNewline& str);
public:
    StringAndNewline() : str_(){}
    StringAndNewline(std::string str) : str_(str){}
    const std::string& str() const noexcept {return str_;}
    std::string release() {return std::move(str_);}
};

在操作符中读取的字符串自动忽略前面的所有空格,而变成由当前语言环境定义的非空白字符序列。这是你想要改变的行为,而且事实证明,这样做非常简单。

初始空格的处理通常由称为哨兵对象的东西执行,该对象还检查流是否有效,如果流位于文件末尾,则设置流的failbit。虽然它的默认行为是在遇到非空白字符之前使用空白字符,但这是由其构造函数中的标志控制的,因此我们可以使用它提供的非常好的封装流有效性检查。

operator>>的字符串重载创建并检查一个哨兵,然后读取,直到遇到空格、流结束或读取失败。我们可以简单地通过自己处理它来确保它的哨兵永远不会遇到空白。

因此,我们的自定义类custom operator>>的最终读入结构看起来像这样:
  • 设置非空格吃哨
  • 检查哨兵,如果它无效,返回失败的流
  • 处理空白
  • 读取数据到包装字符串
  • 返回流

因为我们只关心空格中的'n'字符,这也很简单:只要在流有效时循环(如果在达到我们的任何一个条件之前空间耗尽,它就像我们想要的那样设置failbit),如果两个条件之一是net,则退出循环:我们得到一个换行字符,或者我们得到一个非空白字符。同样,非常简单:

std::istream& operator>>(std::istream& in, StringAndNewline& str){
    std::istream::sentry sentry{in, true}; // make a sentry that doesn't eat whitespace
    if(!sentry){return in;} // check the sentry
    std::locale
        presentLocale{}; // get the present locale
    char presentChar;
    while(in.get(presentChar)){ // while the stream is valid
        if(presentChar == 'n'){ // if we get a newline
            str.str_ = "\n"; // set the string to an escaped newline
            break; // exit the loop
        }
        // if we get a non-whitespace character
        else if(!std::isspace(presentChar, presentLocale)){
            in.unget(); // replace the character in the stream
            in >> str.str_; // take advantage of the existing string operator
            break; // done with loop
        }
    }
    return in; // return the istream, whatever state it might be in
}

完成后,为了便于打印,我们设置一个ostream操作符:

std::ostream& operator<<(std::ostream& out, const StringAndNewline& str){
    return out << str.str();
}

和测试我们的代码:

int main (){
    std::istringstream file(
        "hellon"
        "worldn"
        "C++ is the best tool"
    );
    StringAndNewline
        wordOrNewline;
    while(file >> wordOrNewline){
        std::cout << wordOrNewline << 'n';
    }
}

打印这个:

hello
n
world
n
C++
is
the
best
tool

就像我们想要的!Live on Coliru

如果您真的想要轻松地将包装器类转换为字符串,您甚至可以编写一个字符串操作符,但我将把它留给您。

尝试使用getline (http://www.cplusplus.com/reference/istream/istream/getline/)。Getline将遍历每一行(直到它看到新的行字符),并在到达文件末尾时返回0。因此,在每次调用getline并打印它之后,也会打印n。这里有一个例子来解决你的问题,randFile是一个随机文件,里面有文本。

  1 #include <iostream>
  2 #include <fstream>
  3 int main(){
  4 
  5   std::ifstream myFile("randFile", std::ifstream::in);
  6   char s[BUFSIZ];
  7 
  8   while(myFile.getline(s, BUFSIZ)){
  9     std::cout << s << std::endl;
 10     std::cout << "\n"<< std::endl;
 11   }
 12 
 13   return 0;
 14 }

首先,您已经在流的构造函数中传递了const char *。其次,流读取器读取字符而不是空格,这就是它如何知道何时切到字符串的原因。

通常我们读取一个二进制文件,有一个读者知道的字符,当我们跳过一行时,它告诉我们著名的n,但它与平台(Win, Unix)不同。