0

So we have a text file with the following data:

Year - Make - Model - Price

2011 Chevrolet Tahoe $30588

There is only 1 space between everything. There is a Dollar Sign ($) in front of the price. We still have to have miles in our code, even if it's not in the data file. I don't know why.

How would I go about getting this information from a text file?

I have tried a bunch of methods, and none of them seem to work.

Here is the code that grabs the information:

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <ctime>
#include "car.h"
using namespace std;

const int number=3;
const int maxPrice=25000;

int main()
{
    int a;
    string b; string c;
    float d; 
    float e;

    car cars [number];
    int i, j;
    float temp; //Price
    int temp2; //Year
    string temp3; //Make
    string temp4; //Model
    float temp5; //Miles        

    ifstream inFile; //declaring the File
    inFile.open("carData.txt");

    for(i=0; i<number; i++)
    {
        //cout << "Enter the YEAR of the car: ";
        inFile >> a;
        cars[i].setYear(a);
        //cout << "Enter the MAKE of the car: ";
        getline(inFile,b);
        cars[i].setMake(b);
        //cout << "Enter the MODEL of the car: ";
        getline(inFile,c);
        cars[i].setModel(c);
        //cout << "Enter the number of MILES on the car: ";
        inFile >> d; 
        cars[i].setMiles(d);
        //cout << "Enter the PRICE of the car: ";
        inFile >> e;
        cars[i].setPrice(e);
        //cout << " " << endl;
    }

    // ...
}

The main continues much further than that, this is just to getline all of the data. I've really been having trouble with this all day. I've seen so many different methods.

harper
  • 13,345
  • 8
  • 56
  • 105

2 Answers2

0

If you used a standard parsing function, such as std::fscanf, then you could take away a lot of your pain. You can find out more about *scanf() and friends from http://en.wikipedia.org/wiki/Scanf_format_string and http://www.cplusplus.com/reference/cstdio/fscanf/.

I normally write C (or python, i'm not choosy ;>) so I'd come up with something like this:

infile = open("datafile"); 
res = 0;
while (res != EOF) {
    res = fscanf(infile, "%d %d %s %s %d",
        &price, &year, &model, &model, &miles);
    if (res < 0) {
        /* error condition from fscanf() */
        (void) fprintf(stderr, "error (%d) from fscanf: %s\n",
            res, strerror(res));
        exit(res);
    }
}

[BTW, the reason exercises like these typically require 'miles' (which are featured in the data snippet you gave, it's missing the final column) is because they usually want you to build on these for ranking the cars based on miles or km travelled vs price vs age].

James McPherson
  • 2,476
  • 1
  • 12
  • 16
0

Ok, so I know it is a bit late but here is a way to achieve your desired results, if you haven't done it already, in c++

The problem is that std::getline will put in the argument string the whole line

So if you have something like this

std::getline(inFile, temp3)

The temp3 will have the value: "Year - Make - Model - Price".

This also sets the cursor to the next line so if you repeat the function

std::getline(inFile, temp3)

then temp3 will be equal to "" as the line after the first is empty(at least in the file that you used as an example). Now to work around this you need to use a stringstream that is a stream but reads it's values from a , drum rolls please, string.

So the basic idea is this: 1->Go to the line that contains the information 2->Use a stringstream to read the data()

Here is an implementation of that idea:

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

using namespace std;

int main()
{
    int a; 
    string b; string c;
    float d; 
    float e;
    //This assumes that the array is correctly initialized 
    car cars [number];
    string tempLine;

    ifstream inFile; 
    inFile.open("carData.txt");  

    //get the cursor past the first line that contains the column names
    std::getline(inFile, tempLine)

    //get the cursor past the second line that is blank
    std::getline(inFile, tempLine)

    //Now we are at the line that interests us
    //I am assuming that the next lines don't have a blank line between them
    unsigned int = 0;
    int numberOfMiles;

    while(std::getline(inFile, tempLine) && i<number)
    {
         std::stringstream iss(tempLine)
         string tempPrice; //this will be the price value with the dollar sign

         //you can also write in expanded form this read, but this works just fine
         iss>>a>>b>>c>>numberOfMiles>>tempPrice; //notice that the price is now a string 

         tempPrice.erase(0,1)//this eliminates the dollar($) sign

         std::stringstream iss1(tempPrice)//new stringstream as we need to read this string 

         iss1>>temp;//I believe this is your price variable 

         cars[i].setYear(a);
         cars[i].setMake(b);
         cars[i].setModel(c);
         cars[i].setMiles(numberOfMiles);
         cars[i].setPrice(temp); //i am assuming that this is how the function in called

         i++;
    }

}

Hope this helps.

ciprianr
  • 191
  • 1
  • 1
  • 15
  • Consider what will happen if a line contains: `2007 Chevrolet Monte Carlo $4995` or any other model name that consists of two or more words. – Edward Mar 27 '14 at 21:34
  • @Edward So is `2007 Mitsubishi Motors Evo Lancer $7889` and in these cases there is no way to determine what data goes in what variable. Building a dictionary or some other way to determine what data any succession of words represents is, i believe, overkill. A solution could be a delimiter character like ',' and simply check each read from the string stream, keep a counter c for the delimiter and put data accordion to that counter(c=1->the year was read, c=2->the make). Given the example file i felt it was best to stick to parsing using that supposed structure. – ciprianr Mar 27 '14 at 22:56
  • An alternative would be to parse the data from the front, picking off the year, and from the back, picking off the price, and then dividing what's left in to model and make. Having the program simply fail without any diagnostic message is not the best option, in my view. – Edward Mar 28 '14 at 00:34
  • @Edward Fair but then you still have the problem of determining how many words go into the make and how many into the model. – ciprianr Mar 28 '14 at 00:50
  • @Edward And in code the only way is to create a dictionary, or some other associative container that might come to mind which would certainly clutter the response. The true, solution in my opinion, is using a delimiter character, which, as i have stated, if i were to write code for a file with that structure (Year , Make , Model , Price) it would fail in the example given by the one who asked the question. That is why i chose not to complicate the answer further. I could have showered some exceptions but that would have cluttered the code and i did not wish for that – ciprianr Mar 28 '14 at 00:56