【问题标题】:What is the best way to slurp a text file into an array/collection of std::string in C++在 C++ 中将文本文件放入 std::string 的数组/集合中的最佳方法是什么
【发布时间】:2013-01-11 18:01:28
【问题描述】:

以What is the best way to read an entire file into a std::string in C++? 的风格,我想问一个类似的问题,除了我希望我的输出是一个包含文本文件中的行的数组/STL 容器。

C#/.net 有相当有用的File.ReadAllLines() 实用函数,一个好的 C++ (STL) 版本应该是什么样的?

【问题讨论】:

标签: c++ stl


【解决方案1】:

在 C++ 中,您可以这样做。

  • 定义一个结构为:

    struct line : std::string 
    {
       friend std::istream & operator >> (std::istream & in, line & ln)
       {
          return std::getline(in, ln);
       }
    };
    
  • 然后这样做:

    std::ifstream file("file.txt");
    std::istream_iterator<line> begin(file), end;
    std::vector<std::string> allLines(begin, end);
    
  • 完成!

通过这种方法,您可以直接使用迭代器对begin 和end。无需使用std::vector&lt;std::string&gt;。请注意,line 可以隐式转换为 std::string。因此,您可以将begin 和end 与标准算法一起使用。

例如,

  • 找出最长的线:

    auto cmp = [](line const &a, line const& b) { return a.size() < b.size(); };
    std::string longestLine = *std::max_element(begin, end, cmp);
    
  • 统计长度大于10的行数:

    auto cmp = [](line const &a) { return a.size() > 10 ; };
    size_t count = std::count_if(begin, end, cmp);
    
  • 等等。这样,您可以直接使用begin 和end。无需使用std::vector。节省内存。

希望对您有所帮助。

【讨论】:

  • 但这会在空白处中断而不是换行符。
  • @leemes:假设已删除。
  • 不错!使用line 技巧,也许OP 甚至可以避免使用vector 并直接使用begin,end 范围,这取决于他打算做什么。
  • 对于初学者来说更复杂,但比直接的命令式方法更优雅。我喜欢!
  • +1 终于找到了缺少“getline”流迭代器的解决方案! (虽然这应该是typedef basic_line&lt;char&gt; line;,对吧?:-))
【解决方案2】:

标准成语:

#include <fstream>
#include <string>
#include <vector>
#include <utility>

std::ifstream infile("file.txt");
std::vector<std::string> v;

for (std::string line; std::getline(infile, line); )
{
    v.push_back(std::move(line));
}

【讨论】:

    【解决方案3】:
    std::ifstream ifs(name);
    std::vector<std::string> lines;
    std::string line;
    while (std::getline(ifs, line))
        lines.push_back(line);
    

    【讨论】:

      【解决方案4】:

      这是my attempt@Nawaz 的想法。我已经避免从std::string 继承,因为我对此感到有些不安:

      #include <iostream>
      #include <iterator>
      #include <vector>
      
      struct Line 
      {
          operator const std::string&() const {return string;}
          std::string string;
      };
      
      std::istream& operator>>(std::istream& in, Line& line)
      {
          return std::getline(in, line.string);
      }
      
      int main()
      {
          std::istream_iterator<Line> begin(std::cin), end;
          std::vector<std::string> allLines(begin, end);
      
          std::cout << allLines.size() << " lines read from file:" << std::endl;
          std::copy(allLines.begin(), allLines.end(),
                std::ostream_iterator<std::string>(std::cout, "|"));
          return 0;
      }
      

      【讨论】:

      • 这样,例如,用户将无法编写line.size()。而且我找不到任何理由说明为什么line 不应该源自std::string。或者说为什么basic_line 不应该源自basic_string。 basic_line 是 basic_string。只是它们不是多态的。
      • 我只会使用Line 将数据编组到std::strings。
      • 我已经从你的回答中知道了。只是我找不到任何令人信服的理由说明class basic_line : public std::basic_string {}; 不是一个好主意。我觉得到目前为止还没有人做过,这就是为什么很多人认为它在必须避免的类别中。
      • 有twoquestions关于不是从std::string派生的。
      • 这些答案中的任何内容都不适用于这种情况。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-10
      • 2016-08-20
      • 2010-11-06
      • 2020-09-26
      • 2010-11-06
      • 2011-05-29
      相关资源
      最近更新 更多