• 0

[C++] getline, string streams, iostreams, and strings


Question

I have a need to parse a file that can have infinite rows and columns of #s per row; however, a white space must separate the #s and a newline character must denote the end of a row, except for the last row.

each row represents the y axis and the columns represent the x axis.

Example:

0 1 1 2'\n'
1'\n'
0 2 2'\n'
1 2 2

I need to be able to extract all the #s for a row, minus the white spaces, but know when the row ends '\n' so that when I go to the next row, I can increment the internal y axis representation.

String streams will auto skip white spaces via setting ios_base::skipws, when using the '>>' operator; however the '>>' also extracts but discards the '\n' which means any check for '\n' doesn't work and the read continues onto the next row without me knowing.

I started looking into getline since it stops at a delimiting character, but then I lose the skipping of whitespaces.

My current solution is a combination (pseudo):

ifstream iPattern("file");
string str;

while ( !iPattern.eof() )
{
	 getline(iPattern, str);

	 stringstream ss(str);	 // bad, I know - only way I know to set a string stream with a string?

	 ss.setf(ios_base::skipws);

	 while ( !ss.eof() )
	 {
		  ss >> x;	// read number - x axis
	  }

	  y++;	 // about to read next row - increment y axis
}

Anyone have a better Idea?

I know I could use peek to check ahead without extracting, but I wanted to avoid using peek as then I'd have to manually advance using seekg, etc.

7 answers to this question

Recommended Posts

  • 0

The first problem that popped into my head was what would happen if the number was more than one digit long.

I suppose you could do it by reading it in line by line and then parsing it. You could read characters until you encounter whitespace, then maybe atoi this to give you a number. Then repeat for the complete line and repeat for all lines in the file. Should work...I think :p

  • 0

apparently the number being more than one digit is not an issue - works the same.

I also found that skipws appears to be assumed as my results are the same without defining it; however, if I specifically set noskipws, the whitespaces are read.

Edited by HeartsOfWar
  • 0

#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
#include <string>
using namespace std;

int main() {
	fstream file;
	file.open("exemple.txtif (!file.is_open()) {
		cout << "Cannot open file. " << endl;
		return 0;
	}
	string line;
	vector<string> allLines;
	while (!file.eof()) {
		getline(file, line);
		allLines.push_back(line);
	}

	string buffer;
	vector< vector<int> > matrix;
	vector<int> matrixLine;
	for (size_t i = 0; i < allLines.size(); i++) {
		stringstream ss(allLines[i]);
		while(ss >> buffer) {
			int value = atoi(buffer.c_str());
			matrixLine.push_back(value);
		}
		matrix.push_back(matrixLine);
		matrixLine.clear();
	}

	for(vector<vector<int> >::const_iterator it = matrix.begin(); it != matrix.end(); it++) {
		for(vector<int>::const_iterator jt = (*it).begin();  jt != (*it).end(); jt++) {
			cout << *jt << " ";
		}
		cout << endl;
	}

}

matrix will contain all your numbers. Of course this code is full of holes, it doesn't protect against any kind of errors, it's very inefficient if the file is large, but for demonstration purposes it does the job alright.

  • 0

I appreciate the reply Dr_Asik, but as you mentioned, that code is extremely overkill and inefficient for what I want / need.

I'm pretty happy with what I've got, was just wondering if anyone could think of a way around having the dual while loops.

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.