Connecting Tech Pros Worldwide Help | Site Map

std::istream_iterator to read whole lines?

 
LinkBack Thread Tools Search this Thread
  #1  
Old December 1st, 2005, 06:45 PM
Marcus Kwok
Guest
 
Posts: n/a
Default std::istream_iterator to read whole lines?

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

  #2  
Old December 1st, 2005, 07:25 PM
Neil Cerutti
Guest
 
Posts: n/a
Default 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
  #3  
Old December 2nd, 2005, 05:45 PM
Marcus Kwok
Guest
 
Posts: n/a
Default 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
 

Bookmarks

Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On

Popular Articles

What is Bytes?

We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights. Get the best answers to your questions from over 220,840 network members.