Reading a line from a file into different variables using fstream - c++

I wonder if there is any way to not ignore spaces when trying to assign a value to name.
I would like to keep this conditional structure* in the while loop but getting the ClientFile >> like getline and not as cin.
*I know I could use substring and find, that is not the idea.
Line example from text file:
1 ; Iron Man ; 10.70
Problem:
The program does not enter the loop because name is being assigned as only Iron.
using namespace std;
int main()
{
ifstream ClientsFile("clients.txt");
int id;
string name;
double money;
char sep1;
char sep2;
while (ClientsFile >> id >> sep1 >> name >> sep2 >> money)
{
cout << "id: " << id << endl << "name: " << name << endl << "money: " << money << endl << endl;
}
return 0;
}
Thanks.

The input operator >> separates on white-space. Instead you might want to use std::getline to read the semicolon separated fields.
Something like
std::string id_string, money_string;
while (std::getline(ClientsFile, id_string, ';') &&
std::getline(ClientsFile, name, ';') &&
std::getline(ClientsFile, money_string))
{
id = std::stoi(id_string);
money = std::stod(money_string);
...
}

Related

How can i read string and integer, on same line from a text file?

I have this example,
On my .txt file i have “Jorge Saraiva 1321312”
my .cpp
string line, nome;
int number;
ifstream ifi("nameOfFile.txt");
if(!ifi.is_open()){
cout << "Error opening file" << ends;
}
{
else{
while( getline(ifi,line) ){
istringstream is(line);
is >> nome;
is >> number;
}
ifi.close();
}
cout << nome << endl << number << ends;
With this i only got first name ("Jorge"), I'm not sure how can i tell compiler when the name/string ends.
You are trying to put string (2nd one) into a number, that is the cause of unexpected output. Directing it to a string should fix that. You can discard the string, doesn't matter.
string line, name, dummy;
int number;
while(getline(ifi, line)){
istringstream iss1(line);
iss1 >> name;
iss1 >> dummy;
iss1 >> number;
}
There's one solution I can see for your problem. If you want to have multiple names (no matter the size) and then a number on front you can take advantage form the isdigit function.
In your while cycle when reading from the file you can add something like:
String temp;
is >> name;
while (is){
is >> temp;
if(isdigit(temp[0])){
int number = atoi(temp.c_str()); }
else {
name += " " + temp;
}
}
That way you can have multiple sized names.
I'm writing on a phone so it's harder but you can get an idea of what I'm talking about. Yet don't forget to include the library.
Mostly, when dealing with csv files, your data is delimited with semicolon or some other character. In you case you dont have it, so you must do more advanced parsing. You may use regexps for that:
#include <regex>
// ...
// Pattern
std::regex pattern("([^\\d]+)\\s*([\\d ]+)" );
// ...
// And instead of istringstream
std::smatch sm;
if (std::regex_match(line, sm, pattern)) {
nome = sm[1];
number = std::stoi(sm[2]);
}
You can choose to keep extracting as an integer, unless successful
int number;
string name;
istringstream record(line);
// keep trying till a number is found.
record >> number;
while (record.fail() && !record.eof()) {
record.clear();
string temp;
record >> temp;
name.append(temp);
record >> number;
}
cout << "Name: " << name << endl;
cout << "Number: " << number << endl;
Complete Code:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main ()
{
string line;
while (getline(cin, line)) {
int number;
string name;
istringstream record(line);
// keep trying till a number is found.
record >> number;
while (record.fail() && !record.eof()) {
record.clear();
string temp;
record >> temp;
name.append(temp);
record >> number;
}
cout << "Name: " << name << endl;
cout << "Number: " << number << endl;
}
return 0;
}
Try this code
string line, firstname,lastname;
int number;
ifstream ifi("nameOfFile.txt");
if (!ifi.is_open())
{
cout << "Error opening file" << ends;
}
else
{
while (ifi>>firstname>>lastname>>number) {}
ifi.close();
}
cout << firstname <<endl<<lastname <<endl << number << ends;

C++ Read in data types string, int double from a file. Put each line of data into a vector of objects

data file:
candy, 1.99, 26
chips, 2.55, 22
//my attempt to read in each line creating a new object for the line
while (getline(inFile, line, '\n')) {
istringstream ss(line);
ss >> name >> price >> amount;
products newProduct(name, price, amount);
item.push_back(newProduct);
}
Right now I am only getting the name and price of only the first line.
How can I read in the entire line storing all three values for all lines in the file?
You've got to handle comma after price:
char comma;
ss >> name >> price >> comma >> amount;
Just to clarify: the name is read with the first comma. Then the stream reads a double - finds a comma and stops here. Then you request to read an int but all it got is... a comma. You need to get rid of it to proceed.
Update:
#include <iostream>
#include <string>
#include <sstream>
int main()
{
std::istringstream file("xxx, 23.0, 11\nyyy, 99.3, 100");
while (!file.eof()) {
std::string line;
std::getline(file, line);
std::istringstream line_stream(line);
std::string name;
double price;
char comma;
int amount;
line_stream >> name >> price >> comma >> amount;
std::cout << "name: " << name << std::endl;
std::cout << "price: " << price << std::endl;
std::cout << "amount: " << amount << std::endl;
std::cout << "===================" << std::endl;
}
}
Try to structure the code like this:
if( inFile.is_open() ){
string line;
while(getline(inFile, line){
...
}
}

Finding a word in C++

I'm able to find the word in my list but I would like to display whatever number there is after the word has been found. My list has names followed by their GPA.
Example...
michael 2.3
Rachel 2.5
Carlos 3.0
I would like to add the feature of displaying the number located after the name once it's found, I declared as int GPA but I'm not sure how to incorporated in my program.
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
string name;
int offset;
string line;
int gpa;
ifstream read_file;
read_file.open("alpha.dat");
cout << "Please enter your name: \n";
cin >> name;
if (read_file.is_open())
{
while (!read_file.eof())
{
getline(read_file, line);
if ((offset = line.find(name)) != string::npos)
{
cout << "the word has been found: \n";
// cout << name << gpa; example to display
}
}
read_file.close();
return 0;
}
As far as I can tell, you just need to output the line that you read from file:
while( getline(read_file, line) )
{
if ((offset = line.find(name)) != string::npos) cout << line << endl;
}
Note that this isn't the best way to find the name. For example, what if the user enters Carl? It will be found as part of the string Carlos. Or indeed, if they enter 2, it will match parts of the GPA for multiple people.
What you can do here is use a string stream to read the name out. Let's assume it contains no spaces, which would make it conform to how you are reading the user's name in. You need to include <sstream>, by the way. Note that you can read out the GPA as part of this same mechanism.
istringstream iss( line );
string thisname, gpa;
if( iss >> thisname >> gpa ) {
if( thisname == name ) cout << name << " " << gpa << endl;
}
Finally, you may want to consider ignoring case when comparing strings. The cheeky way is to just use the old C functions for this. I know there are C++ methods for this, but none are as simple as good old stricmp from <cstring>:
if( 0 == stricmp(thisname.c_str(), name.c_str()) ) {
cout << name << " " << gpa << endl;
}
You can split line using stringstream, and store it into a vector, like this:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <vector>
using namespace std;
int main()
{
string name;
int offset;
string line;
int gpa;
ifstream read_file;
read_file.open("alpha.dat");
cout << "Please enter your name: \n";
cin >> name;
if (read_file.is_open())
{
while (!read_file.eof())
{
getline(read_file, line);
if ((offset = line.find(name)) != string::npos)
{
cout << "the word has been found: \n";
stringstream iss(line);
vector<string> tokens;
string str;
while (iss >> str)
tokens.push_back(str);
cout << tokens[0] << tokens[1];
}
}
read_file.close();
return 0;
}
}
You can replace getline(read_file, line)... with:
read_file >> name >> gpa;
if (name == search_name)
cout << name << " " << gpa << endl;

How to read in a set of values from a text file, then go to the next line and do the same

Im trying to read a list like this one
James John 15 5 1
Douglas Frank 23 8 1
Bnejamin Zach 17 1 4
and store each value into a a separate variable. The names are strings, and the other numbers are floats and an int. I can get the data from one line so far, but I dont know how to go onto the next line and do the same. Here is my code so far.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
ifstream employees;
string lastname, firstname, lastname1, firstname1, lastname2, firstname2;
float base, sales, base1, sales1, base2, sales2;
int years, years1, years2;
employees.open("employees.txt");
while (employees)
{
employees >> lastname >> firstname >> base >> sales >> years;
I want to keep it as simple as possible, I dont know user defined functions, arrays, or vectors at all yet. So is there a simple function that will just end the line at years; and go to the next line and carry on?
Thanks.
Use an array. Whenever you end up with "I want to add a number to this variable because I want more than one", if the number reaches more than 2, then you should really use an array (unless very special cases).
You may also want to use a struct to store your different values (firstname, lastname, base, sales and years) - that way, you only get a single array, rather than several different arrays.
Since this is C++, arrays means vector. In other words:
struct employee
{
string firstname, lastname;
float base, sales;
int years;
};
vector<employee> emp_table;
employee e;
while (employees >> e.firstname >> e.lastname >> e.base >> e.sales >> e.years)
{
emp_table.push_back(e);
}
Note I put the input of employees as the while-condition. This avoids an extra loop iteration and "pushing back" a second copy of the last entry when you have reached end of file.
There are many ways in C++ to accomplish what you are trying to do. One approach that allows for data validation is to use the std::getline function to read the file one line at a time and then use a std::stringstream to parse the data.. This allows you to validate the data and continue processing if the data on a line is malformed.
[As Mats noted you can use a data structure and std::vector to make storing and managing the data easier.]
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
struct employee
{
std::string firstname;
std::string lastname;
float base;
float sales;
int years;
};
int main()
{
std::ifstream employeeFile;
employeeFile.open("employees.txt");
std::string tmpLine;
std::vector<employee> employeeTable;
// read in an entire line at a time
while(std::getline(employeeFile, tmpLine))
{
// Place the input line into a stream that reads from
// a string instead of a file.
std::stringstream inputLine(tmpLine);
// Try parsing the data. The ! operator is used here to check
// for errors. Since we expect the data to be in a specific format
// we want to be able to handle situations where the input line
// may be malformed. For example, encountering a string where
// a number should be.
employee e;
if(!(inputLine >> e.firstname >> e.lastname >> e.base >> e.sales >> e.years))
{
// ... error parsing input. Report the error
// or handle it in some other way.
continue; // keep going!
}
// Add to the vector
employeeTable.push_back(e);
}
return 0;
}
You can use getline inside your loop to retrieve each line and then use it with a stringstream
Something like:
string line;
while(getline(employees,line))
{
//doSomething
}
If you can't use arrays to store them easily, you can put a counter to know at which line you're at, but this is very repetitive, and the number of lines in your file cannot vary:
string line;
for (int count = 1 ; count <= 3 ; count++)
{
getline(employees,line);
istringstream iss(line);
if (count == 1)
{
iss >> lastname >> firstname >> base >> sales >> years;
}
else if (count == 2)
{
iss >> lastname1 >> firstname1 >> base1 >> sales1 >> years1;
}
else if (count == 3)
{
iss >> lastname2 >> firstname2 >> base2 >> sales2 >> years2;
}
}
Opening and reading a file properly is harder than learning what an array is. If you don't use an array you have to use too many variables to hold all your data, and you have to repeatedly write the code to read from the file, rather than writing it once in a loop.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
string firstNames[3];
string lastNames[3];
float heights[3];
float weights[3];
int ages[3];
ifstream infile("data.txt");
if(!infile)
{
cout << "Couldn't open file!" << endl;
return 1;
}
int count = 0;
while (infile >> firstNames[count]
>> lastNames[count]
>> heights[count]
>> weights[count]
>> ages[count] )
{
++count;
}
infile.close();
for (int i = 0; i<count; ++i) {
cout << firstNames[i] << " "
<< lastNames[i] << " "
<< heights[i] << " "
<< weights[i] << " "
<< ages[i] << " " << endl;
}
return 0;
}
--output:--
James John 15 5 1
Douglas Frank 23 8 1
Bnejamin Zach 17 1 4
Compare to this disaster:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
string firstName0,firstName1, firstName2;
string lastName0, lastName1, lastName2;
float height0, height1, height2;
float weight0, weight1, weight2;
int age0, age1, age2;
ifstream infile("data.txt");
if(!infile)
{
cout << "Couldn't open file!" << endl;
return 1;
}
infile >> firstName0 >> lastName0 >> height0 >> weight0 >> age0;
infile >> firstName1 >> lastName1 >> height1 >> weight1 >> age1;
infile >> firstName2 >> lastName2 >> height2 >> weight2 >> age2;
infile.close();
cout << firstName0 << " "
<< lastName0 << " "
<< height0 << " "
<< weight0 << " "
<< age0 << endl;
cout << firstName1 << " "
<< lastName1 << " "
<< height1 << " "
<< weight1 << " "
<< age1 << endl;
cout << firstName2 << " "
<< lastName2 << " "
<< height2 << " "
<< weight2 << " "
<< age2 << endl;
return 0;
}
--output:--
James John 15 5 1
Douglas Frank 23 8 1
Bnejamin Zach 17 1 4
Look at all the code you have to repeat.
Note that when you use an array, the variable names become firstNames[0] (v. firstName0), lastNames[0] (v. lastName0), etc., and firstNames[1] (v. firstName1) and lastNames[1] (v. lastName0).

Taking Input through a string in c++

In C, suppose I need to take input from a string
int num,cost;
char *name[10];
printf("Enter your inputs [quantity item_of_name at cost]");
scanf("%d%*c%s%*c%*s%*c%d",&num,name[0],&cost);
printf("quantity of item: %d",num);
printf("the cost of item is: %d",cost);
printf("the name of item is: %d",name[0]);
INPUT
1 book at 12
OUTPUT
Quantity of item is: 1
The cost of item is: 12
The name of item is: book
Now I want to do the same thing in C++. And I have no idea how to approach. gets() returns the whole string.Is there any specific function that I am missing out on? Please help.
int num,cost;
std::string name;
std::cout << "Enter your inputs [quantity item_of_name at cost]: ";
if (std::cin >> num >> name >> cost)
{ } else
{ /* error */ }
You will want to add errorhandling
In C++ you should rather use cin, cout and string from standard library.
In c++, std::stream provides the read and write communication with the user through the >> operator.
Your code translates to
int num,cost;
std::string name;
std::cout << "Enter your inputs [quantity item_of_name at cost]" << std::flush;
std::cin >> num >> name;
std::cin >> at; // skip the at word
std::cin >> cost;
std::cout << "quantity of item: " << num << std::endl;
std::cout << "the cost of item is: " << cost << std::endl;
std::cout << "the name of item is: " << name << std::endl;
You could use iostream's cin.
int num,cost;
char *name[10];
std::cout <<"Enter your quantity"<<std::endl;
std::cin>> num;
std::cout<<" Enter the cost"<<std::endl;
std::cin>>cost;
std::cout<<"Enter the name"<<std::endl;
std::cout<<"The quantity of the item is: "<<num<<" costing: "<<cost<<" for "<<name[0]<<std::endl;
and then of course you could also use std::string instead of char*.
Or streamline the cin's as cin >> num >> cost >> name;
Also, as Griwes noted, you will want to perform error checking on your results.