Custom stream manipulator

I am trying to read a file where each line contains data separated by commas. I passing each line to a istringstream object to treat that line as a stream. Now I would like to write a custom stream manipulator that reads data until it hits a comma or eof.

1
2
3
4
5
6
7
8
9
istream& my_read(string str, istream& in) 
{
  if ((in >> ws).get() == ',') 
  {
    in.ignore();
  }else
    in.unget();
  return in;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
  istringstream ins;
  ins.str("hi , 32.5 , , 43");
  string s;
  my_read(s,ins);
  ins >> s;
  cout << s << endl;
  double val;
  my_read(s,ins);
  ins >> val;
  cout << val << endl;
  my_read(s,ins);
  ins >> s;
  cout << s << endl;


I don't know if this is a proper way, but either way it has a problem if there are empty fields like in the 3rd attempt to read, in that case the read string is "," where is should be empty. How can I solve this problem?. Also please note that I only want to use stl and no external libraries.
From what I am reading, I think that you don't even need a custom stream manipulator. You can just use getline

http://cplusplus.com/reference/string/getline/

1
2
3
4
std::istringstream ins("hi, 32.5, , 43");
std::string s;

std::getline(ins, s, ',');
I have to admit that I'd prob just use std::string's functionality to deal with each line (you did say that you were reading your file a line at a time, into a std::string, and then using that to initialize a std::istringstream?)

What do you want to do with the extracted values, by the way. I assume it's more that displaying them.

I think a istringstream based solution would only likely be a curiousity...

Andy

PS What you talking about is a stream extraction operator, not a manipulator (those are things like std::setw(), std::hex(), as defined in <iomanip>)
Last edited on
@andywestken: for now I just want to store the values in vectors, and thanks for correcting me, you were right they are stream extraction procedures.

@stewbond: thanks a lot, this approach is actually much simpler, I went ahead and wrote 3 functions to read int, string, and double from the string.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
istream& read_str(istream& in, string& str, char delim)
{
  return getline(in, str, delim);
}

istream& read_double(istream& in, double& n, char delim)
{
  string str;
  getline(in, str, delim);
  n = atof(str.c_str());
  return in;
}

istream& read_int(istream& in, int& n, char delim)
{
  string str;
  getline(in, str, delim);
  n = atoi(str.c_str());
  return in;
}


Everything is working, but any comments or advice will be greatly appreciated.
Everything is working, but any comments or advice will be greatly appreciated.


You could simplify by using a template instead?
Disclaimer: code below not tested.
1
2
3
4
5
6
7
8
9
10
template <typename T>
istream & read_something(istream &is, T &t, char delim)
{
    string s;

    getline(is, s, delim);
    istringstream iss(s);
    iss >> t;
    return is;
}


Edit: should test it.

Edit 2: must be specialized for std::strings or else it will break them up into words.
Last edited on
Out of interest, do you have to deal with strings with embedded commas?

(Some variations of the csv format do allow lines like

"Hello, world!", 42, 3.1415, 3e8

with the parser being expected to return the string without the quotes.)

Andy
@andy: luckily no
@Catfish2: thanks for the advice, I'll get on it.
Topic archived. No new replies allowed.