Connecting Tech Pros Worldwide Forums | Help | Site Map

std::istream_iterator to read whole lines?

Marcus Kwok
Guest
 
Posts: n/a
#1: Dec 1 '05
I am writing a program to read in a file, do some processing, then write
it out to a different file. I really like the idiom I use for output:

// std::vector<std::string> vec;
// std::ofstream out;
std::copy(vec.begin(),
vec.end(),
std::ostream_iterator<std::string>(out, "\n"));



Is there a way to do the same thing for input that will read whole
lines? I tried the obvious thing:

// std::ifstream in;
std::copy(std::istream_iterator<std::string>(in),
std::istream_iterator<std::string>(),
std::back_inserter(vec));

but it separates on whitespace so every word is a different element in
the vector. I would like it to do the same thing as

// std::string line;
while (std::getline(in, line)) {
vec.push_back(line);
}


It's not a big deal or anything. I would just like the the two
operations to look consistent.

--
Marcus Kwok

Neil Cerutti
Guest
 
Posts: n/a
#2: Dec 1 '05

re: std::istream_iterator to read whole lines?


On 2005-12-01, Marcus Kwok <ricecake@gehennom.net> wrote:[color=blue]
> I am writing a program to read in a file, do some processing,
> then write it out to a different file. I really like the idiom
> I use for output:
>
> // std::vector<std::string> vec;
> // std::ofstream out;
> std::copy(vec.begin(),
> vec.end(),
> std::ostream_iterator<std::string>(out, "\n"));
>
>
>
> Is there a way to do the same thing for input that will read
> whole lines? I tried the obvious thing:
>
> // std::ifstream in;
> std::copy(std::istream_iterator<std::string>(in),
> std::istream_iterator<std::string>(),
> std::back_inserter(vec));
>
> but it separates on whitespace so every word is a different
> element in the vector. I would like it to do the same thing as
>
> // std::string line;
> while (std::getline(in, line)) {
> vec.push_back(line);
> }[/color]

Implement a line-based input iterator. It should be a snap.

You could implement a line type instead, with a suitable
operator>>, but I don't like the idea as much.

--
Neil Cerutti
Marcus Kwok
Guest
 
Posts: n/a
#3: Dec 2 '05

re: std::istream_iterator to read whole lines?


Neil Cerutti <leadvoice@email.com> wrote:[color=blue]
> On 2005-12-01, Marcus Kwok <ricecake@gehennom.net> wrote:[color=green]
>> I am writing a program to read in a file, do some processing,
>> then write it out to a different file. I really like the idiom
>> I use for output:
>>
>> // std::vector<std::string> vec;
>> // std::ofstream out;
>> std::copy(vec.begin(),
>> vec.end(),
>> std::ostream_iterator<std::string>(out, "\n"));
>>
>>
>>
>> Is there a way to do the same thing for input that will read
>> whole lines? I tried the obvious thing:
>>
>> // std::ifstream in;
>> std::copy(std::istream_iterator<std::string>(in),
>> std::istream_iterator<std::string>(),
>> std::back_inserter(vec));
>>
>> but it separates on whitespace so every word is a different
>> element in the vector. I would like it to do the same thing as
>>
>> // std::string line;
>> while (std::getline(in, line)) {
>> vec.push_back(line);
>> }[/color]
>
> Implement a line-based input iterator. It should be a snap.[/color]

OK, my template technique is not too strong yet, so here is what I came
up with. Basically, I copied the implementation of istream_iterator
from the STL that comes with VS .NET 2003 (I believe they still use
Dinkumware) but renamed some of the implementation items, and added a
specialization for std::string, so this may not be the simplest or most
elegant way. If anyone knows a simpler way to specialize
istream_iterator for std::string then please enlighten me. Also, please
disregard some of the funky spacing, as I'm trying to get it to fit on
80 character lines for the NG post.

#include <iostream>
#include <string>
#include <fstream>
#include <algorithm>
#include <vector>

template <class T,
class Ch = char,
class Tr = std::char_traits<Ch>,
class Dist = std::ptrdiff_t>
class my_istream_iterator : public std::iterator<std::input_iterator_tag,
T,
Dist,
const T*,
const T&> {
public:
typedef my_istream_iterator<T, Ch, Tr, Dist> my_t;
typedef Ch char_type;
typedef Tr traits_type;
typedef std::basic_istream<Ch, Tr> istream_type;

// construct singular iterator
my_istream_iterator() : my_istream(0) { }

// construct with input stream
my_istream_iterator(istream_type& s) : my_istream(&s) { getval(); }

// return designated value
const T& operator*() const { return my_val; }

// return pointer to class object
const T* operator->() const { return &**this; }

// preincrement
my_istream_iterator& operator++()
{
getval();
return *this;
}

// postincrement
my_istream_iterator operator++(int)
{
my_t tmp = *this;
++*this;
return tmp;
}

// test for iterator equality
bool equal(const my_t& rhs) const { return my_istream == rhs.my_istream; }

protected:
// get a T value if possible
void getval()
{
if (my_istream != 0 && !(*my_istream >> my_val))
my_istream = 0;
}

istream_type* my_istream; // pointer to input stream
T my_val; // lookahead value (valid if my_istream is not null)
};

// specialization for std::string
template <>
void my_istream_iterator<std::basic_string<char>, char,
std::char_traits<char>, std::ptrdiff_t>::getval()
{
if (my_istream != 0 && !(std::getline(*my_istream, my_val)))
my_istream = 0;
}

// my_istream_iterator template operators
// test for my_istream_iterator equality
template <class T, class Ch, class Tr, class Dist>
inline bool operator==(const my_istream_iterator<T, Ch, Tr, Dist>& lhs,
const my_istream_iterator<T, Ch, Tr, Dist>& rhs)
{
return lhs.equal(rhs);
}

template <class T, class Ch, class Tr, class Dist>
inline bool operator!=(const my_istream_iterator<T, Ch, Tr, Dist>& lhs,
const my_istream_iterator<T, Ch, Tr, Dist>& rhs)
{
return !(lhs == rhs);
}



int main(int argc, char* argv[])
{
std::ifstream in(argv[1]);
std::vector<std::string> vec;

std::copy(my_istream_iterator<std::string>(in),
my_istream_iterator<std::string>(),
std::back_inserter(vec));

std::ofstream out(argv[2]);
std::copy(vec.begin(),
vec.end(),
std::ostream_iterator<std::string>(out, "\n"));

return 0;
}

// vim: tabstop=4 shiftwidth=4

--
Marcus Kwok
Closed Thread