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;
Related
So I am trying to read a .txt file in c++ program. Each line in the text file has firstName, lastName and yearlySalary (e,g, Tomm Dally, 120000).
I can seem to read a file properly - it skips the first column (firstName) and stops reading the data in after first line. Why is that?
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
using namespace std;
int main()
{
string fName;
string lName;
double yearlyPay;
double backPayDue;
double newAnualSalary;
double newMonthlyWage;
int numOfEmployees = 0;
double totalBackPayDue = 0;
ifstream empSalariesOld("EmpSalaries.txt");
ofstream empSalariesNew("EmpSalariesNew.txt");
if (!empSalariesOld.fail())
{
while (empSalariesOld >> fName)
{
empSalariesOld >> fName >> lName >> yearlyPay;
std::cout << fName << " " << lName << " " << yearlyPay << endl;
numOfEmployees++;
}
}
empSalariesOld.close();
empSalariesNew.close();
system("pause");
return 0;
}
You are not reading the lines correctly.
When your while statement calls empSalariesOld >> fName for the first time, it reads an employee's first name. Then, inside the loop body, when you call empSalariesOld >> fName >> lName >> yearlyPay, >> fName reads the employee's last name (because you already read the first name), then >> lName reads the employee's salary, and >> yearlyPay tries to read the next employee's first name and fails!
Try something more like the following instead. Use std::getline() to read a whole line, and then use std::istringstream to parse it:
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
#include <sstream>
using namespace std;
int main()
{
string fName;
string lName;
double yearlyPay;
//...
int numOfEmployees = 0;
ifstream empSalariesOld("EmpSalaries.txt");
ofstream empSalariesNew("EmpSalariesNew.txt");
if (empSalariesOld)
{
string line;
while (getline(empSalariesOld, line))
{
istringstream iss(line);
if (iss >> fName >> lName >> yearlyPay) {
std::cout << fName << " " << lName << " " << yearlyPay << endl;
++numOfEmployees;
}
}
}
empSalariesOld.close();
empSalariesNew.close();
cout << "Press any key";
cin.get();
return 0;
}
However, if the lines actually have a comma between the name and salary like you showed (Tomm Dally, 120000), then try the following instead:
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
#include <sstream>
using namespace std;
int main()
{
string name;
double yearlyPay;
//...
int numOfEmployees = 0;
ifstream empSalariesOld("EmpSalaries.txt");
ofstream empSalariesNew("EmpSalariesNew.txt");
if (empSalariesOld)
{
string line;
while (getline(empSalariesOld, line))
{
istringstream iss(line);
if (getline(iss, name, ',') && (iss >> yearlyPay))
std::cout << name << " " << yearlyPay << endl;
++numOfEmployees;
}
}
}
empSalariesOld.close();
empSalariesNew.close();
cout << "Press any key";
cin.get();
return 0;
}
I am trying to create a program that will make an array of data entered until a stop commands is entered and have it log it into a text document. I am getting a crash of Microsoft Visual Studio after i enter the Fist name and Last name fields.
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;
int main(void) {
string firstName;
string lastName;
string stream;
int outputString;
string dataOutput;
string dataArray[1];
bool askData = true;
int i = 0;
ofstream outfile("data.txt");
while (askData) {
cout << "Type First then Last Name or \"$Stop\" to save and exit" << "\n" << "First: ";
getline(cin, firstName);
if (firstName == "$Stop") {
askData = false;
}
else {
cout << "Last: ";
cin >> lastName;
cout << "\n\n\n";
dataOutput = firstName + " " + lastName + "; ";
dataArray [1 + i] = dataOutput;
i++;
}
cout << dataOutput;
}
outfile << dataArray;
outfile.close();
return 0;
}
EDIT:
Also tried.
string dataArray[];
then later assigning it to an incrementing variable.
int i = 0;
dataArray[i];
i++;
Can you tell me why this doesnt work?
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;
I want to find a string in a file and replace it with user input.
Here is my rough code.
#include <iostream>
#include <fstream.h>
#include <string.h>
int main(){
istream readFile("test.txt");
string readout,
search,
replace;
while(getline(readFile,readout)){
if(readout == search){
// How do I replace `readout` with `replace`?
}
}
}
UPDATE
Here is the code that solved my problem
test.txt:
id_1
arfan
haider
id_2
saleem
haider
id_3
someone
otherone
C++ Code:
#include <iostream>
#include <fstream>
#include <string>
using namesapce std;
int main(){
istream readFile("test.txt");
string readout,
search,
firstname,
lastname;
cout << "Enter the id which you want to modify";
cin >> search;
while(getline(readFile,readout)){
if(readout == search){
/*
id remains the same
But the First name and Last name are replaced with
the user `firstname` and `lastname` input
*/
cout << "Enter new First name";
cin >> firstname;
cout << "Enter Last name";
cin >> lastname;
}
}
}
Suppose:
A user searches for id id_2. After that user enter First name and Last name Shafiq and Ahmed.
After runing this code the test.txt File must modify the record like that:
…
id_2
Shafiq
Ahmad
…
Only the id_2 record changes, the remaining file will stay the same.
This should work. I used string::find to find the desired substring within each line, and string::replace to replace it if something has been found.
Edit: I forgot about the case where the word occurs multiple times per line. Added a while to fix this.
#include <fstream>
#include <iostream>
using namespace std;
int main(int argc, char **argv)
{
ifstream in(argv[1]);
ofstream out(argv[2]);
string wordToReplace(argv[3]);
string wordToReplaceWith(argv[4]);
if (!in)
{
cerr << "Could not open " << argv[1] << "\n";
return 1;
}
if (!out)
{
cerr << "Could not open " << argv[2] << "\n";
return 1;
}
string line;
size_t len = wordToReplace.length();
while (getline(in, line))
{
while (true)
{
size_t pos = line.find(wordToReplace);
if (pos != string::npos)
line.replace(pos, len, wordToReplaceWith);
else
break;
}
out << line << '\n';
}
}
I would do what #stefaanv said:
#include <iostream>
#include <fstream.h>
#include <string.h>
int main(){
ostream outFile("replaced.txt");
istream readFile("test.txt");
string readout;
string search;
string replace;
while(getline(readFile,readout)){
if(readout == search){
outFile << replace;
}
else {
outFile << readout;
}
}
}
Edit: the above solution works if the information on each line is independent of the information on the other lines. In your update, the information on the name lines is dependent on the information on the id lines. So, to extend the above technique, you'll need to maintain state in the while loop that indicates when you've reached the end of one data block.
#include <iostream>
#include <fstream.h>
#include <string.h>
int main(){
ostream outFile("replaced.txt");
istream readFile("test.txt");
string readout;
string search, Fname, Lname;
unsigned int skipLines = 0;
cout << "Enter id which you want Modify";
cin >> search;
cout << "Enter new First name";
cin >> Fname;
cout << "Enter Last name";
cin >> Lname;
while(getline(readFile,readout)) {
if (skipLines != 0) {
skipLines--;
continue;
}
else if (readout == search) {
outFile << search << endl;
outFile << Fname << endl;
outFile << Lname << endl;
skipLines = 2;
}
else {
outFile << readout;
}
}
}
A slightly more elegant approach would be to store each data block in a struct, which allows you to use overloaded operators << & >>. This makes the code for file reading & writing more clear - it's practically the same as the code for the "data on each line is independent" situation.
#include <iostream>
#include <fstream.h>
#include <string.h>
struct NameRecord {
string id;
string fname;
string lname;
friend std::ostream& operator<<(std::ostream &os, const NameRecord &src);
friend std::istream& operator>>(std::istream &is, NameRecord &dst);
};
std::ostream& operator <<(std::ostream &os, const NameRecord &src) {
os << src.id << endl << src.fname << endl << src.lname << endl;
return os;
}
std::istream& operator >>(std::istream &is, NameRecord &dst) {
// may need to have more code to ignore whitespace, I'm not sure
if (is.good ()) {
is >> dst.id;
}
if (is.good ()) {
is >> dst.fname;
}
if (is.good ()) {
is >> dst.lname;
}
return is;
}
int main(){
ostream outFile("replaced.txt");
istream readFile("test.txt");
NameRecord inRecord, replaceRecord;
cout << "Enter id which you want Modify";
cin >> replaceRecord.id;
cout << "Enter new First name";
cin >> replaceRecord.Fname;
cout << "Enter Last name";
cin >> replaceRecord.Lname;
while (readFile.good()) {
// the >> operator reads the whole record (id, fname, lname)
readFile >> inRecord;
// the << operator writes the whole record
if (inRecord.id == replaceRecord.id) {
outFile << replaceRecord;
}
else {
outFile << inRecord;
}
}
}
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, char **argv) {
if (argc < 4) {
cout << "Invalid input" << endl;
cout << "\tchange <old_word> <new_word> <file_list>";
}
fstream fs;
string tmp;
string oldw = argv[1];
string neww = argv[2];
for (int i = 3; i < argc; i++) {
fs.open(argv[i] , ios::in);
while (!fs.eof()) {
getline(fs, tmp);
while (tmp.find(oldw) != string::npos)
tmp.replace(tmp.find(oldw), sizeof(oldw), neww);
cout << tmp << endl;
}
}
fs.close();
return 0;
}
Usage:
./a.out old_word new_word filename
You probably meant to write:
tmp.replace(tmp.find(oldw), oldw.length(), neww);
for this to work properly. sizeof() will most likely always return 4.
How can I read input line(type string) with whitespace? I tried getline but it goes into infinite loop. Following is my code.
#include <iostream>
#include <cstring>
#define MAX 50 //size of array
//Used G++ 4.6.3 compiler
using namespace std;
int main() {
struct Manager {
string name;
int age;
int working_years;
string phone;
int salary;
}info[MAX];
char inp; //To choose options
int array_pos = 0; //Current position in array of Manager structure
string search_name; //Manager name you want to search
cout << "Press 'i' to insert manager information or 's' to search for manager information by name or 'a' to abort: ";
cin >> inp;
while(inp != 'a') {
int search_num = 0; //array position at which search result is found
int found = 0;
if (inp == 'i' || inp == 's') {
if (inp == 'i') {
int k = array_pos;
cout << "Enter the information of the manager no "<<k+1<<" is : ";
cout << "Enter the Name : ";
//infinte loop occurs
getline(info[array_pos].name, '\n');
//cin >> info[array_pos].name;
cout<<"Enter manager age : ";
cin >> info[array_pos].age;
cout << "Enter manage working years : ";
cin >> info[array_pos].working_years;
cout << "Enter manager phone no. : ";
cin >> info[array_pos].phone;
cout << "Enter manager salary : ";
cin >> info[array_pos].salary;
array_pos++;
}
if (inp == 's') {
cout << "Enter the manager name you want to search : ";
cin >> search_name;
for(int i = 0; i < array_pos; i++) {
//using str1.compare(str2) to compare manager name
if(info[i].name.compare(search_name) == 0) { //manager name found in array of structure
found = 1;
search_num = i;
cout << "Name : " << info[search_num].name << "\n";
cout << "Age: " << info[search_num].age << "\n";
cout << "Working Years: " << info[search_num].working_years << "\n";
cout << "Phone No. : " << info[search_num].phone << "\n";
cout << "Salary : " << info[search_num].salary << "\n";
} //end of if loop for comparing string
} //end of for loop for searching
if(found == 0)
cout << "No Manager by this name exist in record" << "\n";
} //end of if loop
} //end of if loop for searching or insertion
if(inp == 'a')
break;
cout << "Press 'i' to insert manager information or 's' to search for manager information by name or 'a' to abort: ";
cin >> inp;
} //end of while loop
return 0;
}
How can I read input line(type string) with whitespace?
std::string line;
if (std::getline(std::cin, line)) {
...
}
Note that apart from checking the return value of std:getline call, you should also avoid mixing >> operator with std::getline calls. Once you decide reading the file line by line, it seems to be cleaner and more reasonable to just make one huge loop and do the additional parsing while using string stream object, e.g.:
std::string line;
while (std::getline(std::cin, line)) {
if (line.empty()) continue;
std::istringstream is(line);
if (is >> ...) {
...
}
...
}
Simplest way to read string with spaces without bothering about std namespace is as follows
#include <iostream>
#include <string>
using namespace std;
int main(){
string str;
getline(cin,str);
cout<<str;
return 0;
}
Solution #1:
char c;
cin >> noskipws; // Stops all further whitespace skipping
while (cin >> c) { // Reads whitespace chars now.
count++;
}
Solution #2:
char c;
while (cin.get(c)) { // Always reads whitespace chars.
count++;
}