Problem reading data from file

Ok, I got this to read the first and the first item in the second line, but it stops after that. There are 3 other items on line 2 that it needs to read and it never goes to the rest of the lines. I just need this figured out before I can go onto the rest of the program. Of course I have been stuck on this for a while and now its due tonight by midnight. I would appreciate anyone's help on this. I am sure its something simple, but I just cant see it.

Here is the data file:
123456 M JMH987 1971 12692
732567 A EUJ618 2012 23645 M DHL358 2010 9742 A LLP519 2001 13280
638025 M RWT175 2011 23999
402857 A IOP825 2011 11111
903728 A ESF285 2009 9999

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * Author:  Jeanine Haenel
 * Class:  CS362
 * Assignment: Week 1, Program 1
 * Program Description: Program reads data from REGISTER.txt.
 * Input: REGISTER.txt
 * Processing:
 * Output: HOUSEHOLDS.txt, VEHICLES.txt
 */

#include<iostream>
#include<fstream>
#include<string>
#include<iomanip>

using namespace std;

//CONSTANTS
const string FILENAME = "REGISTER.txt";
const int CURRENT_YEAR = 2013;
const float AUTO_ROAD_FEE = 24.00;
const float CYCLE_ROAD_FEE = 12.00;
const int FULL = 20;                                   //line counter, when reaches 20, redisplays header
const float LICENSE_PERCENT = .0025;                   //percentage of msrp for license fee
const float AGE_RANGE1 = 5;                          //age range 1 for car or motorcycle
const float RANGE1_PERCENT_MSRP_AUTO = .03;       //percentage of msrp for car
const float RANGE1_PERCENT_AGE_AUTO = .0015;      //percentage of msrp for car per age
const float RANGE1_PERCENT_MSRP_CYCLE = .025;     //percentage of msrp for motorcycle
const float RANGE1_PERCENT_AGE_CYCLE = .0009;     //percentage of msrp for motorcycle per age
const float AGE_RANGE2_MIN = 6;                    //minimum for age range 2, car or motorcycle
const float AGE_RANGE2_MAX = 10;                  //max for age range 2, car or motorcycle
const float RANGE2_PERCENT_MSRP_AUTO = .0275;     //percentage of msrp for car
const float RANGE2_PERCENT_AGE_AUTO = .0012;      //percentage of msrp for car per age
const float RANGE2_PERCENT_MSRP_CYCLE = .0225;    //percentage of msrp for motorcycle
const float RANGE2_PERCENT_AGE_CYCLE = .0009;     //percentage of msrp for motorcycle per age
const float AGE_RANGE3_MIN = 11;                  //minimum for age range 3, car or motorcycle
const float AGE_RANGE3_MAX = 15;                  //max for age range 3, car or motorcycle
const float RANGE3_PERCENT_MSRP_AUTO = .025;      //percentage of msrp for car
const float RANGE3_PERCENT_AGE_AUTO = .0009;      //percentage of msrp for car per age
const float RANGE3_PERCENT_MSRP_CYCLE = .02;      //percentage of msrp for motorcycle
const float RANGE3_PERCENT_AGE_CYCLE = .0009;     //percentage of msrp for motorcycle per age
const float AGE_RANGE4 = 15;                           //age range 4 for car or motorcycle
const float AGE_RANGE4_TAX_AUTO = 20.00;           //flat rate for age range 4 for car
const float AGE_RANGE4_TAX_CYCLE = 10.00;          //flat rate for age range 4 for motorcycle



//FUNCTION PROTOTYPES
void getRoadFee(char type, float& roadFee);
void getTax(char type, float msrp, int age, float& tax);

int main()
{
     int houseid = 0, year = 0, full = 0, age = 0, lineNum = 0;
     float msrp = 0, roadFee = 0, licenseFee = 0, tax = 0, total = 0;
     char type, ch;
     string plate;
     int noOfVehicles;

     ifstream inRegister;          //ifstream
     inRegister.open (FILENAME.c_str());          //open file

     if(!inRegister)          //if not open
          cout << "Error opening input file " << FILENAME << endl;
     else
          inRegister >> houseid;      //prime read

     do
     {
          inRegister >> type >> plate >> year >> msrp;
          cout << houseid << " " << type << " " << plate << " " << year << " " << msrp << endl;
          age = CURRENT_YEAR - year;
          licenseFee = msrp * LICENSE_PERCENT;
          getTax(type, msrp, age, tax);
          getRoadFee(type, roadFee);
          total = roadFee + licenseFee + tax;
          inRegister >> houseid;

     }while(inRegister && ch != '\n');       //while open

     inRegister.close();



          //display
          //customer << fixed << showpoint << setprecision(2);
          //customer << left << setw(14) << custCode << setw(3) << " $ " << totalUtilityCharge << endl;

//if(lineNum = FULL)           //REDISPLAY HEADER
          //{
              // system("pause");
              // system("CLS");
               //function to output to screen;
              // lineNum = 0; //reset to 0
          //}


     system("pause");
     return 0;
}

void getRoadFee(char type, float& roadFee)
{
     switch (type)
          {
               case 'A':
                    roadFee = AUTO_ROAD_FEE;
                    break;
               case 'M':
                    roadFee = CYCLE_ROAD_FEE;
                    break;
          }
}

void getTax(char type, float msrp, int age, float& tax)
{
     if(type == 'A' && age <= AGE_RANGE1)
          tax = (RANGE1_PERCENT_MSRP_AUTO * msrp) - ((RANGE1_PERCENT_AGE_AUTO * msrp) * age);
     if(type == 'A' && age >= AGE_RANGE2_MIN || age <= AGE_RANGE2_MAX)
          tax = (RANGE2_PERCENT_MSRP_AUTO * msrp) - ((RANGE2_PERCENT_AGE_AUTO * msrp) * age);
     if(type == 'A' && age >= AGE_RANGE3_MIN || age <= AGE_RANGE3_MAX)
          tax = (RANGE3_PERCENT_MSRP_AUTO * msrp) - ((RANGE3_PERCENT_AGE_AUTO * msrp) * age);
     if(type == 'A' && age > AGE_RANGE4)
          tax = AGE_RANGE4_TAX_AUTO;
     if(type == 'M' && age <= AGE_RANGE1)
          tax = (RANGE1_PERCENT_MSRP_CYCLE * msrp) - ((RANGE1_PERCENT_AGE_CYCLE * msrp) * age);
     if(type == 'M' && age >= AGE_RANGE2_MIN || age <= AGE_RANGE2_MAX)
          tax = (RANGE2_PERCENT_MSRP_CYCLE * msrp) - ((RANGE2_PERCENT_AGE_CYCLE * msrp) * age);
     if(type == 'M' && age >= AGE_RANGE3_MIN || age <= AGE_RANGE3_MAX)
          tax = (RANGE3_PERCENT_MSRP_CYCLE * msrp) - ((RANGE3_PERCENT_AGE_CYCLE * msrp) * age);
     if(type == 'M' && age > AGE_RANGE4)
          tax = AGE_RANGE4_TAX_CYCLE;
}
Are some of the fields in an individual record optional? You seem to expect a type/plate/year/msrp/houseid for every record, but they aren't present in the input file.

If we put the missing newlines into the input file (which shouldn't make any difference as far as your parsing goes) we get:

123456 M JMH987 1971 12692
732567 A EUJ618 2012 23645 
       M DHL358 2010 9742 
       A LLP519 2001 13280
638025 M RWT175 2011 23999
402857 A IOP825 2011 11111
903728 A ESF285 2009 9999


Which is obviously going to throw things off. You'll be trying to read a letter into a number which will put the input stream into an error state.
closed account (o3hC5Di1)
Hi there,

I may be wrong, but something seems off at the input of line 2:


//line 1
123456 M JMH987 1971 12692
//line2
732567 A EUJ618 2012 
23645  M DHL358 2010 
9742   A LLP519 2001 13280
//line 3
638025 M RWT175 2011 23999


All items except those in line 2 have 2 numbers at the end of them.

My guess is that it will try to read M (2nd item in 2nd line) into an int (houseid of the next line), because it has extracted M's id as the price for the previous item, which will make the streams' failbit to be set and the loop terminate.

I'm not sure how to handle this - because both the houseid ant the msrp are ints, so there'e not really a way to distinguish between them. Hopefully one of the experts here can come up with a solution for it.

Sorry I couldn't be of more help.

All the best,
NwN
Last edited on
I am supposed to read the houseids and when there are multiple vehicles in one line it should keep count of them (which I havent gotten to the counting part). Just another hurdle for me. So, line two would have 3 different vehicles in it.
Nothing wrong with line two, it should have the household id, type (M or A), plate number, year, value. So, if there are more than one vehicle there will be only one houseid, then after the first vehicle it will go directly to the type of the vehicle and so on.

So, it lists:
house type plate year value type plate year value
house type plate year value
house type plate year value type plate year value type plate year value
Last edited on
closed account (o3hC5Di1)
What you could do is check for the errorstate of the stream within the loop.
If the failbit is set, that means an extraction failed, so you could recover from it:

1
2
3
4
if( inRegister.fail())
{
    //recover
}


It woudln't be so easy though, because at that point the harm was already done, the ID was already assigned to the msrp of the previous record.

A cheat would be to check if the id is higher than 100000, that seems to be the only way to determine the difference between a houseid and an msrp.

All the best,
NwN
Try the following:

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
#include<iostream>
#include<fstream>
#include<string>
#include <sstream>

int main()
{
     std::ifstream inRegister("register.txt");  

    std::string line ;
    while ( std::getline(inRegister, line) )
    {
        int houseid ;
        std::istringstream record(line) ;

        record >> houseid ;
        std::cout << houseid << '\n' ;

        char type ;
        std::string plate ;
        int year ;
        float msrp ;

        while ( record >> type >> plate >> year >> msrp )
            std::cout << '\t' << type << ' ' << plate << ' ' << year << ' ' << msrp << '\n' ;
    }
}
closed account (o3hC5Di1)
Nothing wrong with line two, it should have the household id, type (M or A), plate number, year, value. So, if there are more than one vehicle there will be only one houseid, then after the first vehicle it will go directly to the type of the vehicle and so on.


Ah, that changes everything.
In that case you want to use getline(), which will fetch the whole line for you.
Insert that whole line into stringstream and extract as you do now:

1
2
3
4
5
6
7
8
9
10
11
12
#include <sstream>

std::string line;
std::getline(std::cin, line);

std::istringstream tmp(line);
line >> houseid; //just do this once for every line

while (tmp.good())  //get the vehicles on the line
{
    tmp >> type >> plate >> year;
}


Hope that helps.

All the best,
NwN

Edit: I'm too slow - glad I came up with the same answer as Cire though :)


Last edited on
Well I thought you guys figured it out, but my teacher is saying that it is not reading the data right. I cannot read it as a string and then pull data from string. I have to read each piece one at a time.

She said it looks like the work of an old C programmer. Yikes, sorry!

So, if anyone has any idea on how to get this to work right I would appreciate the help. I am just at a loss now. I guess I will keep researching and rereading my book and notes, not that they are much help.

I will have to turn my program in late and lose 2% each day it's late.

Thanks for trying!
Well I thought you guys figured it out, but my teacher is saying that it is not reading the data right. I cannot read it as a string and then pull data from string. I have to read each piece one at a time.

She said it looks like the work of an old C programmer. Yikes, sorry!


If I may say so, your teacher sounds like she doesn't know what she's talking about.

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
#include<iostream>
#include<fstream>
#include<string>
#include <cctype>

bool endOfRecord(std::istream & is)
{
    while ( std::isspace(is.peek()) && is.peek() != '\n' )
        is.ignore() ;

    return is.peek() == '\n' ;
}

int main()
{
     std::ifstream inRegister("register.txt");  

     int houseid ;

    while ( inRegister >> houseid  )
    {
        std::cout << houseid << '\n' ;

        char type ;
        std::string plate ;
        int year ;
        float msrp ;

        while ( !endOfRecord(inRegister) && (inRegister >> type >> plate >> year >> msrp) )
            std::cout << '\t' << type << ' ' << plate << ' ' << year << ' ' << msrp << '\n' ;
    }
}


If you can count on the format of the file not including extra whitespace between tokens, you could go with:

1
2
3
4
bool endOfRecord(std::istream& is )
{
    return is.peek() == '\n' ;
}


for the endOfRecord implementation, but it is a more brittle one. Alternately, you could check the type of the next non-space character encountered to determine whether you've encountered the end of a record, but that also involves checking explicitly for eof.
Last edited on
Topic archived. No new replies allowed.