Gadesxion
Gadesxion

Reputation: 483

Reading/parsing text file input c++

A little background: I am working on a sliding block puzzle for a school project and this is our first using C++ instead of Java. This is the first time I have had to implement something that reads data from a file.

I have a simple question regarding reading input from a text file. I understand how to read the file line by line and hold each line in a string, I want to know if I can parse the string into different data types as the file is read.

Currently I am reading each line and storing them as strings in a vector for parsing later, and I know there must be a much simpler way to implement this

The first line holds 2 integers which will indicate the length and width of the grid, the following lines will have 4 integers and a char for use as arguments when creating the blocks.

My question is this, if I read the file character by character instead, is there a function I can use that will detect if the character is an integer or a char (and ignore the spaces) so I can store them immediately and create the block objects as the file is read? How would i deal with integers >10 in this case?

EDIT: Just noting I am using fstream to read the files, I am unfamiliar with other input methods

A sample input:

4  4
3  1  2  1  b
1  1  1  1  a 

Upvotes: 4

Views: 64289

Answers (4)

Loki Astari
Loki Astari

Reputation: 264401

I would read each line into a string (as you have been doing).
Then I would read the tokens from that line into the appropriate variables.

The operator>> when applied to a stream will convert the next value in a stream into the correct type. If this is not possable it sets flags on the stream indicating failure that are easy to test.

 int  x;
 stream >> x; // ignores white space then: reads an integer from the stream into x

 char c;
 stream >> c; // ignores white space then: reads an char from the stream into c

 double d;
 stream >> d; // ignores white space then: reads an double from the stream into d

Assuming your input:

4  4
3  1  2  1  b
1  1  1  1  a 

Not knowing what the the values mean I will put my assumptions in comments.

// Assume that stream is a std::fstream already opened to you file.

std::string line1;
std::getline(stream, line1);           // reads "4 4" into `line1`

std::stringstream  line1stream(line1); // convert line1 into a stream for reading.
int a;
int b;
line1stream >> a >> b;   // reads "4 4" from 'line1' into a (now 4) b (now 4)
if (!stream || !line1stream)
{
     // failed reading the first line.
     // either reading the line failed (!stream)
     // or     reading 2 integers from line1stream failed (!line1stream)
     throw SomeException("Failed");
}


std::string line2;
std::getline(stream, line2);           // reads "3  1  2  1  b" into line2

std::stringstream line2stream(line2);  // convers line2 into a stream for reading.
int  data[4];
char c;

line2stream >> data[0] >> data[1] >> data[2] >> data[3] >> c;
if (!stream || !line2stream)
{
     // failed reading the second line.
     // either reading the line failed (!stream)
     // or     reading 4 integers and one char from line2stream failed (!line2stream)
     throw SomeException("Failed");
}

Upvotes: 1

rob05c
rob05c

Reputation: 1233

If you can assert each type, I suggest using stream operators, like you would with cin.

#include <fstream>

using namespace std;

int main()
{
    fstream fileStream;
    fileStream.open("inputfile.txt");

    int firstNumber;
    fileStream >> firstNumber;

    char firstChar;
    fileStream >> firstChar;
}

This way, you can read by value, instead of reading by line and then parsing the line. Just read in every value you need into a variable, as you discover you need it, like that.

Upvotes: 4

Kerrek SB
Kerrek SB

Reputation: 477040

To detect whether a piece of string can be parsed as an integer, you just have to parse it and see if you succeed. The best function for that would probably be std::strtoul(), since it can be made to tell you how many characters it consumed, so that you can continue parsing after that. (See the man page for details.)

However, if you already know the format of your file, you can use iostream formatted extraction. This is quite straightforward:

#include <fstream>


std::ifstream infile("thefile.txt");

int n1, n2, x1, x2, x3, x4;
char c;

if (!(infile >> n1 >> n2)) { /* error, could not read first line! Abort. */ }

while (infile >> x1 >> x2 >> x3 >> x4 >> c)
{
    // successfully extracted one line, data is in x1, ..., x4, c.
}

Another alternative is to read every line into a string (using std::getline), then creating a stringstream from that line, and parsing the stringstream with >>. This has the added benefit that you can discover and skip bad lines and recover, while in the direct formatted extraction I presented above, you cannot recover from any error.

Upvotes: 5

cooky451
cooky451

Reputation: 3510

ifstreams are also istreams, so you can use the same operator >> as with std::cin.

int main()
{
    std::ifstream s("test.txt");
    if (s.is_open())
    {
        int i, j, k;
        s >> i >> j >> k;
    }
}

Note that this is way not the fastest way of parsing, but that is probably irrelevant to you.

Upvotes: 1

Related Questions