是否有可以逐行迭代文件的 C++ 迭代器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2291802/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there a C++ iterator that can iterate over a file line by line?
提问by thehouse
I would like to get an istream_iterator-style iterator that returns each line of the file as a string rather than each word. Is this possible?
我想获得一个 istream_iterator 样式的迭代器,它将文件的每一行作为字符串而不是每个单词返回。这可能吗?
采纳答案by Manuel
EDIT:This same trick was already posted by someone else in a previous thread.
编辑:同样的技巧已经被其他人在上一个线程中发布了。
It is easy to have std::istream_iterator
do what you want:
std::istream_iterator
做你想做的事很容易:
namespace detail
{
class Line : std::string
{
friend std::istream & operator>>(std::istream & is, Line & line)
{
return std::getline(is, line);
}
};
}
template<class OutIt>
void read_lines(std::istream& is, OutIt dest)
{
typedef std::istream_iterator<detail::Line> InIt;
std::copy(InIt(is), InIt(), dest);
}
int main()
{
std::vector<std::string> v;
read_lines(std::cin, std::back_inserter(v));
return 0;
}
回答by Matteo Italia
The standard library does not provide iterators to do this (although you can implement something like that on your own), but you can simply use the getline function(not the istream method) to read a whole line from an input stream to a C++ string.
标准库不提供迭代器来执行此操作(尽管您可以自己实现类似的东西),但您可以简单地使用getline函数(而不是 istream 方法)将整行从输入流读取到 C++ 字符串.
Example:
例子:
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
ifstream is("test.txt");
string str;
while(getline(is, str))
{
cout<<str<<endl;
}
return 0;
}
回答by Rexxar
Here is a solution. The exemple print the input file with @@ at the end of each line.
这是一个解决方案。该示例在每行末尾使用@@ 打印输入文件。
#include <iostream>
#include <iterator>
#include <fstream>
#include <string>
using namespace std;
class line : public string {};
std::istream &operator>>(std::istream &is, line &l)
{
std::getline(is, l);
return is;
}
int main()
{
std::ifstream inputFile("input.txt");
istream_iterator<line> begin(inputFile);
istream_iterator<line> end;
for(istream_iterator<line> it = begin; it != end; ++it)
{
cout << *it << "@@\n";
}
getchar();
}
Edit :Manuel has been faster.
编辑:曼努埃尔的速度更快。
回答by Patrick
You could write your own iterator. It's not that hard. An iterator is just a class on which (simply speaking) the increment and * operators are defined.
您可以编写自己的迭代器。这并不难。迭代器只是一个类(简单地说)定义了增量和 * 运算符。
Look at http://www.drdobbs.com/cpp/184401417to get started writing your own iterators.
查看http://www.drdobbs.com/cpp/184401417开始编写您自己的迭代器。
回答by coelhudo
You can use istreambuf_iterator instead of istream_iterator. It doesn't ignore control characters like istream_iterator.
您可以使用 istreambuf_iterator 而不是 istream_iterator。它不会忽略像 istream_iterator 这样的控制字符。
code.cpp:
代码.cpp:
#include <iterator>
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream file("input.txt");
istreambuf_iterator<char> i_file(file);
istreambuf_iterator<char> eof;
std::string buffer;
while(i_file != eof)
{
buffer += *i_file;
if(*i_file == '\n')
{
std::cout << buffer;
buffer.clear();
}
++i_file;
}
return 0;
}
input.txt:
输入.txt:
ahhhh test *<-- There is a line feed here*
bhhhh second test *<-- There is a line feed here*
output:
输出:
ahhhh test
bhhhh second test
回答by winvicta
In a related thread iterate-over-cin-line-by-linequoted above, Jerry Coffin described "another possibility (which) uses a part of the standard library most people barely even know exists." The following applies that method (which was what I was looking for) to solve the iterate-over-file-line-by-line problem as requested in the current thread.
在上面引用的相关线程中,逐行迭代,Jerry Coffin 描述了“另一种可能性(它)使用了大多数人几乎不知道存在的标准库的一部分。” 下面应用该方法(这是我正在寻找的)来解决当前线程中请求的逐行迭代文件问题。
First a snippet copied directly from Jerry's answer in the related thread:
首先是直接从相关线程中 Jerry's answer 复制的片段:
struct line_reader: std::ctype<char> {
line_reader(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table() {
static std::vector<std::ctype_base::mask> rc(table_size, std::ctype_base::mask());
rc['\n'] = std::ctype_base::space;
return &rc[0];
}};
And now, imbue the ifstream with the custom locale as described by Jerry, and copy from infstream to ofstream.
现在,用 Jerry 描述的自定义语言环境填充 ifstream,并从 infstream 复制到 ofstream。
ifstream is {"fox.txt"};
is.imbue(locale(locale(), new line_reader()));
istream_iterator<string> ii {is};
istream_iterator<string> eos {};
ofstream os {"out.txt"};
ostream_iterator<string> oi {os,"\n"};
vector<string> lines {ii,eos};
copy(lines.begin(), lines.end(), oi);
The output file ("out.txt") will be exactly the same as the input file ("fox.txt").
输出文件(“out.txt”)将与输入文件(“fox.txt”)完全相同。
回答by NicholasM
Here is a pretty clean approach that uses boost::tokenizer. This returns an object providing begin()
and end()
member functions; for a complete interface, see the documentation of the tokenizer
class.
这是一个使用boost::tokenizer的非常干净的方法。这将返回一个对象提供begin()
和end()
成员函数;有关完整的接口,请参阅tokenizer
类的文档。
#include <boost/tokenizer.hpp>
#include <iostream>
#include <iterator>
using istream_tokenizer = boost::tokenizer<boost::char_separator<char>,
std::istreambuf_iterator<char>>;
istream_tokenizer line_range(std::istream& is);
{
using separator = boost::char_separator<char>;
return istream_tokenizer{std::istreambuf_iterator<char>{is},
std::istreambuf_iterator<char>{},
separator{"\n", "", boost::keep_empty_tokens}};
}
This hardcodes char
as the stream's character type, but this could be templatized.
这硬编码char
为流的字符类型,但这可以模板化。
The function can be used as follows:
该函数可以如下使用:
#include <sstream>
std::istringstream is{"A\nBB\n\nCCC"};
auto lines = line_range(is);
std::vector<std::string> line_vec{lines.begin(), lines.end()};
assert(line_vec == (std::vector<std::string>{{"A", "BB", "", "CCC"}}));
Naturally, it can also be used with an std::ifstream
created by opening a file:
当然,它也可以用于std::ifstream
通过打开文件创建的:
std::ifstream ifs{"filename.txt"};
auto lines = line_range(ifs);