I am trying to read a file using ifstream in c++. The file has 5 columns and last column is the name column which contains the name with multiple spaces in the name. Some names have 1 and some have 2 spaces.
I want to read the name in a single variable instead of multiple ones.
I have used :
while (infile >> recordDate >> relativeHumidity >> airTemp >> tempUnit >> name1 >> name2 >>> name3){}
Above code works fine for the names having 2 spaces but when it reads the line which has a name with one space the name3 varialble stores the first value of next line.
Date RelativeHumidity Air Temp Units Meteorologist Name
5/13/2009 1.096000 34.630000 C D. Bernoulli
7/1/1903 0.313000 77.470000 f Sir C. Wren
Use getline to read to the end of line, that way you only need one variable.
while ((inFile >> recordDate >> relativeHumidity >> airTemp >> tempUnit) &&
std::getline(inFile, name))
{
}
You could try something like the following:
while (infile)
{
infile >> recordDate >> relativeHumidity >> airTemp >> tempUnit;
getline(infile, name);
const auto trim = [](const auto& s) {
return s.substr(
s.find_first_not_of(' ', 0),
s.find_last_not_of(' ', 0)
);
};
name = trim(name);
}
Related
I have a problem with C++ File input.
I have a file with n lines that each lines contains 4 variables. I need them read them into a hash table that I created. My problem is that I can't read the file correct way.
For example here the input file variables:
line id cont uniq-number Band
0 10 B 02020213456 DaftPunk
1 11 A 02030213456 Dazy
and so on..
The main problem is to read each variable in line until file EOF.
So I need read in each line these variables id, cout, uniq-number and band and while it is reading put these data inside a hash table to process them even further in C++.
Example
cout << "File" << endl;
int date,id;
string group,line,ch;
datar d;
hasher h1;
ifstream inFile;
inFile.open("file.txt");
while (getline (inFile,line))
{
// "reads" file each variable
inFile >> id >> ch >> date >> group;
//add these variable in line one to first hash line
d.id = id;
d.data = ch;
d.date= date;
d.group = group;
h1.add(d);
//must repeat until file EOF for each line
}
inFile.close();
In this code,
while (getline (inFile,line))
{
// "reads" file each variable
inFile >> id >> ch >> date >> group;
//add these variable in line one to first hash line
d.id = id;
d.data = ch;
d.date= date;
d.group = group;
h1.add(d);
//must repeat until file EOF for each line
}
the getline reads a line.
Then the loop body reads items from the next line.
Instead of that
inFile >> id >> ch >> date >> group;
do e.g.
istringstream linestream( line );
linestream >> id >> ch >> date;
getline( linestream, group );
The last getline in order to handle possible spaces in a name.
This assumes that the name is last on the line, as it currently is, and it assumes that it's not the case that every second line should be ignored (i.e., that that was bug).
It's also a good idea to add failure checking.
If a stream operation fails then the stream enters a failure state, and you can check that via the member function .fail().
I am having trouble getting istringstream to continue in while loop shown below. The data file is shown below also. I use getline from Input file to get the first line and put it in a istringstream lineStream. It passes through the while loop once, then it reads in the second line and goes back to the beginning of the loop and exits rather than continue through the loop. I have no clue why, if anyone could help I would thankful.
EDIT: The reason I have this while loop condition is because the file may contain lines of erroneous data. Therefore, I want to make sure the line I am reading in has the proper form shown below in the data file.
while(lineStream >> id >> safety){//keeps scanning in xsections until there is no more xsection IDs
while(lineStream >> concname){//scan in name of xsection
xname = xname + " " +concname;
}
getline(InputFile, inputline);//go to next xsection line
if(InputFile.good()){
//make inputline into istringstream
istringstream lineStream(inputline);
if(lineStream.fail()){
return false;
}
}
}
Data FILE
4 0.2 speedway and mountain
7 0.4 mountain and lee
6 0.5 mountain and santa
In the presented code, …
while(lineStream >> id >> safety){//keeps scanning in xsections until there is no more xsection IDs
while(lineStream >> concname){//scan in name of xsection
xname = xname + " " +concname;
}
getline(InputFile, inputline);//go to next xsection line
if(InputFile.good()){
//make inputline into istringstream
istringstream lineStream(inputline);
if(lineStream.fail()){
return false;
}
}
}
… the inner declaration of lineStream declares a local object, which ceases to exist when the execution passes out of that block, and which doesn't affect the stream used in the outer loop.
One possible fix is to invert the code a little bit, like this:
while( getline(InputFile, inputline) )
{
istringstream lineStream(inputline);
if(lineStream >> id >> safety)
{
while(lineStream >> concname)
{
xname = xname + " " +concname;
}
// Do something with the collected info for this line
}
}
struct data
{
int record;
string fName;
string lName;
string phoneNum;
};
string line, lastname, firstname, phone;
vector<data> readContent()
{
inFile.open("data.txt");
vector<data> myData;
char recordstring[4];
data datas;
inFile.clear();
while(inFile >> recordstring)
{
int records;
records = atoi(recordstring);
datas.record = records;
getline(inFile, firstname, ' ');
datas.fName = firstname;
getline(inFile, lastname, ' ');
datas.lName = lastname;
getline(inFile, phone, '\n');
datas.phoneNum = phone;
myData.push_back(datas);
}
inFile.close();
return myData;
}
This is the input file (data.txt):
1000 q q 1
1001 w w 2
1002 e e 3
1003 r r 4
1004 t t 5
This is what the debugger shows for the first line in the file:
http://i.imgur.com/uRGeuvj.png
Can anyone see what is wrong with it?
It should be 1000 being the record, q for fname, q for lname and 1 for phonenum (for the first line). All I am doing is storing each line in an struct instance (data) and then store that into a vector to be used later.
If you want to read from a file word by word, then stay with >>. If you want to read it line by line then use std::getline, but don't mix these two in this manner.
Also note that you have:
declared char recordstring[4]
tried to initialize it using std::cin >> recordstring
tried to convert it to int using atoi
...while simple >> used to fill a variable of type int would do. Note that the size of recordstring is 4, which is big enough to hold 3 characters + null-terminating '\0'
Actually the whole reading could be simple as:
vector<data> myData;
data d;
while(inFile >> d.record >> d.fName >> d.lName >> d.phoneNum) {
myData.push_back(d);
}
inFile >> recordstring does not consume the trailing whitespace, so the first getline() call returns an empty string because the first character it consumes is the whitespace.
If the file format is fixed as shown, simply do following :-
while(inFile >> datas.record >> datas.fName >> datas.lName >> datas.phoneNum)
myData.push_back(datas);
Your logic seems to skip white space for recordstring
It seems that it's not separating the word within the space.
Trying to separate the words in between, and stored it in first and second.
cin >> name; //input name
stringstream file (name);
getline(file,first, ' '); //seperate the name with the first name and last name using space
getline(file,second, ' ');
Replace
cin >> name;
with
getline(cin, name); //input name
cin >> reads only upto the first space. You would have realized this if you done a cout << name; to check what's getting read - this is the first step of debugging.
When you read the initial input with cin >> name; that only reads up to the first white space character.
You then try to break that into two pieces at white space, which it doesn't contain.
Easy way:
cin >> first >> second;
Alternatively, if you start with std::getline(cin, name); instead of cin >> name;, then the rest should work correctly.
I have a text file with a line like:
James Dean 10 Automotive 27010.43
and I need to read that file and put each of the 4 above into arrays.
char nameArray[MAX][NAME_MAX];
int yearArray[MAX];
char departmentArray[MAX][DEP_MAX];
double payArray[MAX];
while(i < MAX && infile) {
infile.getline(nameArray[i], 20);
infile >> yearArray[i];
infile.getline(departmentArray[i], 15);
infile >> payArray[i];
cout << nameArray[i] << " " << yearArray[i] << " " << departmentArray[i] << " " << fixed << setprecision(2) << payArray[i] << endl;
i++;
}
The code is cut down just to give you an idea of what I am trying to do, but when I run this, I get something like:
James Dean -858993460 -92559631349317830000000000000000000000000000
000000000000000000.00
Thanks for the help.
==== Edit ==========================================
I changed from getline to get, thanks for that. I have to use get and not >> because some of the lines I am reading in are more than just "James Dean", they are up to 20 char long...ex: "William K. Woodward" is another one.
So, if I just use get, then it reads the first line in fine, but then I get the same messed up text for the second line.
Here is the code:
infile.get(nameArray[i], 20);
infile >> yearArray[i];
infile.get(departmentArray[i], 15);
infile >> payArray[i];
The getline functions takes an input stream and a string to write to. So, two getline calls read in two lines. Your input mechanism is broken. Either, use getline or the stream extraction operator (i.e. >>) but not both.
If you plan to use getline you need to parse the string (which is effectively one line of input) into tokes, and then store them in appropriately typed arrays. The second and fourth tokens are numbers, hence you will need to convert these from string to int or double.
The operator >> approach:
string name, surname;
int year;
double pay;
while (infile) {
infile >> name >> surname >> year >> department >> pay;
namearray[ i ] = name + " " + surname;
// ...
payarray[ i ] = pay;
++i;
}
The getline approach:
string line;
while (getline(infile, line)) {
parse(line, tokens);
namearray[ i ] = token[ 0 ] + " " + token[ 1 ];
// ...
payarray[ i ] = strTodouble(token[ 4 ]);
++i;
}
// parse definition
void parse(string line, vector<string>& token) {
// roll your own
}
double strToDouble(string s) {
// ...
}
I dont see where you define infile but I will assume that it is an ifile . In that case you should use it the same way u use cin to get input.
Why do you do a getline () ?
That function will stop only at an '\n' char or at an EOF char. So it means, you start reading the int after the end of the line, some random data.
Correct me if i'm wrong, but are there 20 or 19 characters in that first string (James Dean) before the number (10) ?