Ignoring whitespace with getline() and assigning variables

Okay, I'm thoroughly confused. My professor assigned a homework assignment which requires me to read an input file, assign text in the input file to variables, then write them to an output file. I'm currently working on opening the input file and assigning text to the variables, but I don't know how to properly use getline() while still ignoring whitespace. Could someone please help me?


So, if this is my input file (ifile.txt):
1
2
3
4
5
6
7
  2.5   2.0   2.0

  2.0   3.0   4.0

  5.0   5.0   5.0

  1     2     3

How can I read each line and assign each number to a variable while ignoring the whitespace?

If line represents the line being read and ifile is the input file name:
getline(ifile, line);
would read the entire line from my understanding.

I've read using "<<" or ">>" ignores whitespace so that'd be the way to do it but I'm not sure how to implement that for getline..

I've also read (from this stackoverflow post: https://stackoverflow.com/questions/20045726/skip-whitespaces-with-getline)
that this would help me:
http://www.cplusplus.com/reference/istream/ws/
But I don't understand how I'm supposed to use that in my own code..

Full Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <string>
#include <fstream>
#include <sstream> // Not sure how to use this yet, if I even need it..
using namespace std;


int main() {
	ifstream fin;
	ofstream fout;
	string ifile, ofile, line;

	// Asking File Names:
	cout << "Enter the input file name: ";
	cin >> ifile;
	cout << "Enter the output file name: ";
	cin >> ofile;

	// Opening the Files:
	fin.open(ifile);
	fout.open(ofile);

    // Work In Progress..
	getline(ifile, line); // makes a variable for the entire read line
	//cin line >> n1 >> n2 >> n3; // Just a guess. Idk..
	cout << "Debug: line is " << line << endl;
	
	// Closing Files:
	ifile.close();
	ofile.close();

	// General Stuff:
	cin.ignore(1000, '\n');
	cin.get();
	return 0;
}

Help would be greatly appreciated! I'd ask my professor but every time people ask my professor questions his answer is "look it up"..

Thanks!
closed account (SECMoG1T)
how it's done using ">>" and "<<"
1
2
3
4
5
6
7
8
///after you have successfully opened fin and fout

double var1,var2,var3;

while(fin>>var1>>var2>>var3)///read the three values from fin
{
    fout<<var1<<" "<<var2<<" "<<var3<<"\n";///write them to the output file
}
Last edited on
You can use a stringstream with the line.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <fstream>
#include <sstream>  // istringstream
#include <string>

int main() {
    std::ifstream fin("ifile.txt");
    if (!fin) {std::cerr<<"error\n"; return 1;}

    std::string line;
    while (std::getline(fin, line)) {
        double a, b, c;
        std::istringstream iss(line);
        iss >> a >> b >> c;

        if (iss) {
            // use a, b, and c
            std::cout<< a <<','<< b <<','<< c <<'\n';
        }
    }
}

@Yolanda Oh okay. Thank you! That looks easy enough. :)

Edit: We haven't learned arrays in class yet but if I wanted to store the variables for each line, could I just create an empty array for each line then append the variables that the while loop condition reads? Basically, my assignment is more difficult than what I described but I'm doing it step by step so I just included the necessary information for this question.

Edit 2: I just tried your solution but it doesn't appear to work. It asks the input and output file names, I input them, then it closes the console window and creates an ofile.txt but it's empty..?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;


int main() {
	ifstream fin;
	ofstream fout;
	string ifile, ofile, line;

	// Asking File Names:
	cout << "Enter the input file name: ";
	cin >> ifile;
	cout << "Enter the output file name: ";
	cin >> ofile;

	// Opening the Files:
	fin.open(ifile);
	fout.open(ofile);

	// Reading the variables and writing them:
	double v1, v2, v3;
	while (fin >> v1 >> v2 >> v3) {
		fout << v1 << " " << v2 << " " << v3 << endl;
	}

	// Closing Files:
	fin.close();
	fout.close();

	// General Stuff:
	//cin.ignore(1000, '\n');
	cin.get();
	return 0;
}


@tpb Thanks for your reply! What does the "iss" and "cerr" do?

Last edited on
closed account (SECMoG1T)
your input file must exist , provide its name if it is in the current working directory or provide its full path to be on the safe side., remember to check if the files opened before attempting to use them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;


int main() {
	ifstream fin;
	ofstream fout;
	string ifile, ofile, line;

	// Asking File Names:
	cout << "Enter the input file name: ";
	cin >> ifile;
	cout << "Enter the output file name: ";
	cin >> ofile;

	// Opening the Files:
	fin.open(ifile);
	fout.open(ofile);
	
	///important: check if both files opened
	if(!fin || !fout)
    {
        std::cout<<"an error occurred attempting to open your files\n";
        return 1;///exit
    }

	// Reading the variables and writing them:
	double v1, v2, v3;
	while (fin >> v1 >> v2 >> v3) {
		fout << v1 << " " << v2 << " " << v3 << endl;
	}

	// Closing Files:
	fin.close();
	fout.close();

	// General Stuff:
	//cin.ignore(1000, '\n');
	cin.get();
	return 0;
}
Last edited on
Oh okay, @Yolanda. I looked closer and realized I had my input file named as ifile.txt.txt instead of ifile.txt. I also added the lines you added. Thanks!
std::cerr is the "error output stream" which is an alternate output stream usually connected to the terminal (like cout) but you can separately redirect them (so for instance, if standard out (cout) was redirected to a file, standard error (cerr) would still display on the terminal. But you can just use std::cout if you want.

iss is a std::istringstream variable. std::istringstream is an "input string stream" which is like a file stream but reads from a string instead of a file, so when you create it you initialize it with a string. Then you read from iss like from a file, and it goes bad if you try to read beyond the "end of file" (end of string) or, for example, if you try to read a number but the next char isn't allowed in that numeric type.

By reading an entire line first and then "parsing" it with istringstream you don't get any newline issues (the newline is read and removed from the line) and you can check that the line actually contains 3 doubles (and nothing else, if you want). You can also detect empty lines, if that's important (but you can also just ignore them).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>  // istringstream
#include <string>

int main() {
    std::ifstream fin("ifile.txt");
    if (!fin) { std::cerr << "error opening file\n"; return 1; }

    // Set floating point output to a fixed two decimal points.
    std::cout << std::setprecision(2) << std::fixed;

    for (std::string line; std::getline(fin, line); ) {

        double a, b, c;
        char extra;

        std::istringstream iss(line);

        iss >> extra;
        if (!iss)
            continue; // empty line (ignore)
        iss.unget(); // must have read a char; put it back

        iss >> a >> b >> c;
        if (!iss) { // not 3 doubles
            std::cerr << "bad line: not 3 doubles: " << line << '\n';
            continue;
        }

        iss >> extra;
        if (iss) { // extra stuff
            std::cerr << "bad line: extra characters on line: " << line << '\n';
            continue;
        }

        std::cout<< a <<", "<< b <<", "<< c <<'\n';
    }
}

Last edited on
closed account (SECMoG1T)
We haven't learned arrays in class yet but if I wanted to store the variables for each
 line, could I just create an empty array for each line then append the variables that the 
while loop condition reads? Basically, my assignment is more difficult than what I described
 but I'm doing it step by step so I just included the necessary information for this question.


what if you had 10,000 .. 1,000,000 lines well that would be a colossal number of arrays , maybe you could use a dynamic container like a vector in that case or if you knew the number of elements stored in your file before hand you could use an array as below;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;


int main() {

	string ifile, ofile, line;

	// Asking File Names:
	cout << "Enter the input file name: ";
	cin >> ifile;
	cout << "Enter the output file name: ";
	cin >> ofile;

	// Opening the Files:
	fin.open(ifile);
	fout.open(ofile);

	///important: check if both files opened
	if(!fin || !fout)
    {
        std::cout<<"an error occurred attempting to open your files\n";
        return 1;///exit
    }

    ///i can determine your file contains 12 elements, if you can't determine before hand use a vector:
    const int arraySize = 12;
    int arrayIndex=0;
    int myArray[arraySize];

	// Reading the variables and storeing them in an array:
	double var;
	while (fin >> var)
    {
       myArray[arrayIndex] = var;
       ++arrayIndex;
	}

	//writing the items into a file 3/line
	arrayIndex=0;
	while(arrayIndex < arraySize)
    {
        if(arrayIndex % 3 ==0)
            fout<<"\n";

        fout<<myArray[arrayIndex]<<" ";
        ++arrayIndex;
    }

	// Closing Files:
	fin.close();
	fout.close();

	// General Stuff:
	//cin.ignore(1000, '\n');
	cin.get();
	return 0;
}
Last edited on

Help would be greatly appreciated! I'd ask my professor but every time people ask my professor questions his answer is "look it up"..


I like that answer, most of the time. Although there are times when you will need explanation for the items you actually looked up.

Your answer to "look it up" should be "I did but I don't understand what they mean by some specific section." (here you actually point to that section of the documentation you referenced).

Learning to find and understand the documentation for standard functions is something that every programmer need to learn to do, and you learn by doing. Make your "favorite search engine" your best friend, use it, abuse it, and get the information you need. Later in your journey to enlightenment you will start using other publicly available libraries that you will need to find and study that documentation as well.



Ah okay, thanks @tpb for the explanation.

That's a good point @yolanda. I'll look into this code more after my classes today or tomorrow. Thanks!

@jlib Yeah. Good idea, I'll try to remember to say that next time. Thanks!

Edit: By the way, do you get a notification when someone quotes your text? If so, how can I quote other people's messages as I don't see a quote button.
Last edited on
Topic archived. No new replies allowed.