【问题标题】:How to read strings with spaces from a ifstream using istream_iterator?如何使用 istream_iterator 从 ifstream 中读取带空格的字符串?
【发布时间】:2019-08-15 01:37:31
【问题描述】:

我想使用istream_iterator逐行读取文本文件,但是当行中有空格时它会失败。

这是一个示例代码:

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

int main(int argc, char** argv)
{
  if (argc != 2) {
    std::cout << argv[0] << " <file-name>" << std::endl;
    return 10;
  }

  std::ifstream _in(argv[1]);
  if (!_in.good()) {
      std::cout << "error reading " << argv[1] << std::endl;
      return 20;
  }

  _in.unsetf(std::ios_base::skipws);

  std::istream_iterator<std::string> _ite(_in);
  std::istream_iterator<std::string> _end;
  std::string _s(*_ite);

  std::cout << "line read " << _s << std::endl;
}

例如,在这个输入文件中: 1;3.14;bla bla -3;0.923;let me go

读取的第一个字符串是1;3.14;bla

有没有办法,还是放弃使用getline

【问题讨论】:

  • 如果您需要“逐行读取文本文件”,那么您很幸运:这恰好是 std::getline 所做的。使用正确的工具,完成正确的工作。而适合这项工作的工具不是流迭代器,而是std::getline

标签: c++ iostream istream-iterator


【解决方案1】:

当读取std::string 时,它会一直读取直到找到第一个空格字符。什么是空格字符是由流的std::locale 定义的,更准确地说是它的std::ctype&lt;char&gt; facet。您可以创建一个std::ctype&lt;char&gt; 构面,它只将’\n’ 视为一个空间,创建一个包含该构面的std::locale 对象,imbue() 具有相应std::locale 的流,它应该可以工作。

【讨论】:

    【解决方案2】:

    没有。不要放弃。使用 C++ 方法。虽然我也会使用std::getline,但我认为它是C-Style。因此,我将把这个函数包装在一个代理类中。

    我觉得你的想法很好,使用std::istream_iterator。这是“更现代”的 C++ 做事方式。最大的优势是您可以在算法中使用istream_iterator

    唯一要解决的问题是将“线”的抽象模型实现到类中。正如我将在下面展示的那样,这相当容易。

    使用代理类是标准方法,您会在此处找到很多关于这样做的示例。

    请看:

    #include <vector>
    #include <string>
    #include <iostream>
    #include <fstream>
    #include <iterator>
    #include <algorithm>
    #include <sstream>
    #include <ios>
    
    
    std::istringstream testFile{R"(Line1Word1 Line1Word2 Line1Word3 
    Line2Word1 Line2Word2
    Line3Word1 Line3Word2 Line3Word3  Line3Word4
    Line4Word1 Line4Word2 Line4Word3
    )"};
    
    struct Line      // ! This is a proxy for the input_iterator and output iterator! 
    {   
        // Input function. Read on line of text file and split it in columns
        friend std::istream& operator>>(std::istream& is, Line& line) {
            return std::getline(is, line.lineTemp ); 
        }
    
        // Output function. 
        friend std::ostream& operator<<(std::ostream& os, const Line& line) {
            return os <<  line.lineTemp; 
        }
    
        // cast to needed result
        operator std::string() const { return lineTemp; }  
        // Temporary Local storage for line
        std::string lineTemp{};  
    };
    
    
    int main()
    {
        std::cout << "\n\nTest 1. Read all lines into a vector:\n";
        std::vector<std::string> allLines {std::istream_iterator<Line>(testFile),std::istream_iterator<Line>() };
        std::copy(allLines.begin(), allLines.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
    
        std::cout << "\n\nTest 2: Display fist 2 in file\n";
        testFile.clear(); testFile.seekg(0,std::ios::beg);
        std::copy_n(std::istream_iterator<Line>(testFile),2,std::ostream_iterator<std::string>(std::cout, "\n"));
    
        testFile.clear(); testFile.seekg(0,std::ios::beg);
        std::cout << "\n\nTest 3: Number of lines in File\n"
            << std::distance(std::istream_iterator<Line>(testFile),std::istream_iterator<Line>());
    
        std::cout << "\n\nTest 4: Use iterator separately\n";
        testFile.clear(); testFile.seekg(0,std::ios::beg);
        // Define the iterator
        std::istream_iterator<Line> lineIterator(testFile);
        // Dereference iterator
        std::cout << *lineIterator << "\n";
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-06
      • 2011-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多