Reputation: 51
I'm having trouble reading from an input file. The input file looks like this
Lionel Messi -10 43
Fernando Torres 9 -29
Cristiano Ronaldo 7 31
Wayne Rooney 10 37
Neymar 17 29
Andres Iniesta 8 32
Robin van Persie 19 20
Lionel Messi 10 43
Xavi Hernandez 6 36
Mesut Özil 10 38
Didier Drogba 10 35
Fernando Torres 9 29
Kaká 10 17
The problem is that I cant use the getline function because I want to store the name into a single variable to store into an array, and the first number into a variable and the second into another variable. I also tried to use the peek function but I have never learned that so I had no success with it. If anyone knows how to read until the end of the name and store it into a single variable that would be much appreciated.
This is what my code looks like when im reading from the input file
while(!fin.eof())
{
fin >> first >> last >> num >> point;
if (num > 0 && point > 0)
{
list[i].firstname = first;
list[i].lastname = last;
list[i].number = num;
list[i].points = point;
i++;
}
else if (num < 0 || point < 0)
{
reject[j].firstname = first;
reject[j].lastname = last;
reject[j].number = num;
reject[j].points = point;
j++;
}
}
This works perfectly if the input has a first and a last name. I know the problem is on the fin >> first >> last >> num >> point;
but i am not exactly sure how to put first and last (and possibly middle) together
Upvotes: 5
Views: 1671
Reputation: 129314
Something like this should work:
std::string str;
while(getline(infile, str))
{
std::string::size_type pos;
pos = str.find_last_of(' ');
if (pos == std::string::npos || pos < 1)
{
cout << "Something not right with this string: " << str << endl;
exit(1);
}
int last_number = stoi(str.substr(pos));
str = str.substr(0, pos-1); // Remove the number and the space.
pos = str.find_last_of(' ');
if (pos == std::string::npos || pos < 1)
{
cout << "Something not right with this string: " << str << endl;
exit(1);
}
int first_number = stoi(str.substr(pos));
str = str.substr(0, pos-1);
// str now contains the "name" as one string.
// ... here you use last_number and first_number and str to do what you need to do.
}
Upvotes: 1
Reputation: 42072
I have implemented a solution to your problem (mostly for my own learning). It works as intended, but it feels a bit lengthy.
#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
#include<vector>
#include<algorithm>
#include<iterator>
struct PlayerData {
std::string name;
int number;
int points;
};
std::ostream& operator<<(std::ostream& os, const PlayerData& p) {
os<<"Name: "<<p.name<<", Number: "<<p.number<<", Points: "<<p.points;
return os;
}
PlayerData parse(const std::string& line) {
PlayerData data;
std::stringstream ss(line);
std::vector<std::string> tokens;
std::copy(std::istream_iterator<std::string>(ss),
std::istream_iterator<std::string>(),
std::back_inserter<std::vector<std::string>>(tokens));
data.points = std::stoi(tokens.at(tokens.size() - 1));
data.number = std::stoi(tokens.at(tokens.size() - 2));
for(auto it=tokens.begin(); it!=tokens.end()-2; ++it) {
data.name.append(" ");
data.name.append(*it);
}
return data;
}
int main(int argc, char* argv[]) {
std::string line;
std::vector<PlayerData> players;
{ // scope for fp
std::ifstream fp(argv[1], std::ios::in);
while(!fp.eof()) {
std::getline(fp, line);
if(line.size()>0) {
players.push_back(parse(line));
}
}
} // end of scope for fp
// print list of players, or do whatever you want with it.
for(auto p:players) {
std::cout<<p<<std::endl;
}
return 0;
}
Compile with a version of g++ supporting C++11 (in my case gcc 4.7.2).
[Prompt] g++ -oparseline parseline.cpp -std=c++11 -O2
[Prompt] ./parseline players.txt
Name: Fernando Torres, Number: 9, Points: -29
Name: Cristiano Ronaldo, Number: 7, Points: 31
Name: Wayne Rooney, Number: 10, Points: 37
Name: Neymar, Number: 17, Points: 29
Name: Andres Iniesta, Number: 8, Points: 32
Name: Robin van Persie, Number: 19, Points: 20
Name: Lionel Messi, Number: 10, Points: 43
Name: Xavi Hernandez, Number: 6, Points: 36
Name: Mesut Özil, Number: 10, Points: 38
Name: Didier Drogba, Number: 10, Points: 35
Name: Fernando Torres, Number: 9, Points: 29
Name: Kaká, Number: 10, Points: 17
Upvotes: 0
Reputation: 110648
You can use std::getline
to extract the lines, the parse the line into a std::vector
of space separated words. Then you know that words.size() - 2
of the words are part of the name. For example:
std::fstream in("in.txt");
std::string line;
// Extract each line from the file
while (std::getline(in, line)) {
std::istringstream line_stream(line);
// Now parse line_stream into a vector of words
std::vector<std::string> words(std::istream_iterator<std::string>(line_stream),
(std::istream_iterator<std::string>()));
int name_word_count = words.size() - 2;
if (name_word_count > 0) {
// Concatenate the first name_word_count words into a name string
// and parse the last two words as integers
}
}
Upvotes: 4
Reputation: 522
1.) Open the file
std::ifstream myFile("somewhere.txt");
2.) Check to see if the file is open
if(myFile.is_open())
3.) Read until end of file
while(!myFile.eof())
4.) Read the first name into a first name array
myFile >> firstName[numberOfPeople];
5.) Read the last name into the last name array
myFile >> lastName[numberOfPeople];
6.) Read the integer into an integer array
myFile >> integer[numberOfPeople];
7.) Increment number of people
numberOfPeople++;
8.) When while is done, close file
myFile.close();
9.) If file did not open, report the error.
else
std::cout << "\nFile did not open. " << std::endl;
You can use the getline function, you just have to parse the string. This can be achieved using strtok.
Upvotes: 0
Reputation: 153899
It looks to me like you need to use getline
, and then parse
the line. One solution for parsing it might be to split the
line just before the first digit, then trim the first half, and
use it for the name, and parse the second half using an
std::istringstream
to read the two numbers. This will fail,
of course, if someone has a digit as part of their name, but
that seems to me to be a legitimate limitation. In other words,
for each line, you'd do:
std::string::iterator first_digit
= std::find_if( line.begin(), line.end(), IsDigit() );
if ( first_digit == line.end() ) {
// format error...
} else {
name = trim( std::string( line.begin(), first_digit ) );
std::istringstream parser( std::string( first_digit, line.end() ) );
parser >> firstNumber >> secondNumber >> std::ws;
if ( !parser || parser.get() != EOF ) {
// format error...
} else {
// Do what ya gotta do.
}
}
Upvotes: 1
Reputation: 1365
Actually, you can use getline(); Use the two parameter method, passing it a stream and '\n' as the delimiter.
Assign the entire line into one string, then split the string using a space as a delimiter, and covert the second two into integers.
Upvotes: 0