Je voudrais obtenir un itérateur de style istream_iterator qui renvoie chaque ligne du fichier sous forme de chaîne plutôt que chaque mot. Est-ce possible?
EDIT: Cette même astuce a déjà été publiée par quelqu'un d'autre dans un fil précédent .
Il est facile d'avoir std::istream_iterator
faites ce que vous voulez:
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;
}
La bibliothèque standard ne fournit pas d'itérateurs pour ce faire (bien que vous puissiez implémenter quelque chose comme ça par vous-même), mais vous pouvez simplement utiliser la fonction getline (pas la méthode istream) pour lire une ligne entière d'un flux d'entrée vers une chaîne C++.
Exemple:
#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;
}
Voici une solution. L'exemple imprime le fichier d'entrée avec @@ à la fin de chaque ligne.
#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 a été plus rapide.
Vous pouvez écrire votre propre itérateur. Ce n'est pas si dur. Un itérateur n'est qu'une classe sur laquelle (simplement parlant) les opérateurs d'incrémentation et * sont définis.
Regardez http://www.drdobbs.com/cpp/184401417 pour commencer à écrire vos propres itérateurs.
Vous pouvez utiliser istreambuf_iterator au lieu de istream_iterator. Il n'ignore pas les caractères de contrôle comme istream_iterator.
code.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:
ahhhh test *<-- There is a line feed here*
bhhhh second test *<-- There is a line feed here*
sortie:
ahhhh test
bhhhh second test
Dans un sujet connexe itérer sur ligne de ligne par ligne cité ci-dessus, Jerry Coffin a décrit "une autre possibilité (qui) utilise une partie de la bibliothèque standard que la plupart des gens connaissent à peine." Ce qui suit applique cette méthode (qui était ce que je cherchais) pour résoudre le problème itérer-sur-fichier-ligne par ligne comme demandé dans le thread actuel.
D'abord un extrait copié directement à partir de la réponse de Jerry dans le fil associé:
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];
}};
Et maintenant, imprégnez l'ifstream avec les paramètres régionaux personnalisés comme décrit par Jerry, et copiez de infstream vers 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);
Le fichier de sortie ("out.txt") sera exactement le même que le fichier d'entrée ("fox.txt").