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.
Related
So I made a function that reads lines from two files and writes them to a vector. Called the function twice, once for each of the files. Now how should I go for writing the content of the vector to a new file? Also, am I doing it correctly?
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <algorithm>
using namespace std;
bool getFile(string filename, vector<string> & vecOfStrs){
ifstream in(filename.c_str());
if (in.fail()) {
cout << "No such file" << "\n";
return 1;
}
string str;
while (getline(in, str))
{
if (str.size() > 0)
vecOfStrs.push_back(str);
}
in.close();
return true;
}
int main(){
vector<string> A;
string lecCourse;
cout << "First file: ";
cin >> lecCourse;
string lab_ex;
cout << "Second file: ";
cin >> lab_ex;
string exit;
cout << "Name of exit file: " << "\n";
cin >> exit;
bool result = getFile(lecCourse, A);
bool result2 = getFile(lab_ex, A);
ofstream output;
output.open(exit.c_str());
if (output.fail()) {
cout << "error" << "\n";
return 1;
}
}
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <algorithm>
using namespace std;
vector<string> A;
bool getFile(string filename, vector<string> & vecOfStrs){
ifstream in(filename.c_str());
if (in.fail()) {
cout << "No such file" << "\n";
return 1;
}
string str;
while (getline(in, str))
{
if (str.size() > 0)
vecOfStrs.push_back(str);
}
in.close();
return true;
}
int main()
{
string lecCourse;
cout << "First file: ";
cin >> lecCourse;
string lab_ex;
cout << "Second file: ";
cin >> lab_ex;
string exit;
cout << "Name of exit file: " << "\n";
cin >> exit;
bool result = getFile(lecCourse, A);
bool result2 = getFile(lab_ex, A);
ofstream output;
output.open(exit.c_str());
for(int i=0;i<A.size();i++)
{
output<<A[i]<<"\n";
}
if (output.fail()) {
cout << "error" << "\n";
return 1;
}
}
Hope!!
This might helps:))
I have some code that takes a list of names + double values from a .txt file and displays these in the command prompt. For this an array of structs is dynamically allocated. The code should know the size of the array based on the first value in the .txt file, which is then followed by the names and associated values. It should then display the list in two parts with names that have an associated double value higher than or equal to 10.000 listed first. If none of the values qualifies, it displays 'None' in the first half.
The program executes, but the debugger gives an exception and the output is not as expected.
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
using namespace std;
struct donor
{
string name;
double contribution = 0;
};
int main()
{
string filename;
ifstream inFile;
cout << "Enter name of data file: ";
cin >> filename;
inFile.open(filename);
cin.clear();
if(!inFile.is_open())
{
cout << "Could not open the file " << filename << endl;
cout << "Program terminating.\n";
exit(EXIT_FAILURE);
}
int amount;
inFile >> amount;
cin.clear();
donor* dlist = new donor[amount];
int i;
while(inFile.good())
{
for(i = 0; i < amount; i++)
{
getline(inFile, dlist[i].name);
cin.clear();
inFile >> dlist[i].contribution;
cin.clear();
}
}
cout << "Here's the list of Grand Patrons:\n";
bool grandpatrons = false;
for(i = 0; i < amount; i++)
{
if(dlist[i].contribution >= 10000)
{
grandpatrons = true;
cout << dlist[i].name << endl;
cout << dlist[i].contribution << endl;
}
}
if(grandpatrons == false)
{
cout << "None" << endl;
}
cout << "Here's the list of Patrons:\n";
for (i = 0; 1 < amount; i++)
{
if (dlist[i].contribution < 10000)
{
cout << dlist[i].name << endl;
cout << dlist[i].contribution << endl;
}
}
delete[] dlist;
return 0;
}
The donorlist.txt file looks like this:
4
Bob
400
Alice
11000
But the output looks like this:
Enter name of data file: donorlist.txt
Here's the list of Grand Patrons:
None
Here's the list of Patrons:
0
0
0
0
The exception that the debugger gives me is:
Exception thrown at 0x5914F3BE (ucrtbased.dll) in 6_9.exe: 0xC0000005: Access violation reading location 0xA519E363.
Now I assume something is going wrong with reading from the dynamically allocated memory. Maybe something is causing me to read from memory beyond the allocated array? I'm having trouble finding exactly where the mistake is being made.
Your problems begin with the wrong amount written in your data file.
Fix it with:
2
Bob
400
Alice
11000
They then continue with the fact that you inccorectly read the file.
Remember: Mixing operator>> and getline() is not as simple as it seems.
You see, operator>> IGNORES newline and space characters until it finds any other character.
It then reads the upcoming characters until it encounters the next newline or space character, BUT DOES NOT DISCARD IT.
Here is where the problem with getline comes in. getline reads EVERYTHING until it encounters newline or a specified delim character.
Meaning, that if your operator>> stops after encountering newline, getline will read NOTHING since it immediately encounters newline.
To fix this, you need to dispose of the newline character.
You can do this by first checking if the next character in the stream is indeed newline and then using istream::ignore() on it;
int next_char = stream.peek();
if(next_char == '\n'){
stream.ignore();
}
A working example of your code would be:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
//Suggestion: class/struct names should start with a capital letter.
struct Donor{
//Suggestion: Use member initializer lists to specify default values.
Donor() : name(), contribution(0){}
string name;
double contribution;
};
int main(){
cout << "Enter the filename: ";
string filename;
cin >> filename;
//Suggestion: Open the file immediately with the filename and use `operator bool` to check if it opened.
ifstream inFile(filename);
if(!inFile){
cout << "Could not open the file " << filename << '\n';
cout << "Program terminating.\n";
exit(EXIT_FAILURE);
}
int amount;
inFile >> amount; //! Leaves '\n'
Donor* donors = new Donor[amount];
for(int i = 0; i < amount; ++i){
switch(inFile.peek()){
case '\n': inFile.ignore();
break;
case EOF: cout << "Donor amount too big!\n";
exit(EXIT_FAILURE);
}
getline(inFile, donors[i].name);
inFile >> donors[i].contribution;
}
cout << "Here's the list of Grand Patrons:\n";
bool grandpatrons_exist = false;
for(int i = 0; i < amount; ++i){
if(donors[i].contribution >= 10000){
grandpatrons_exist = true;
cout << donors[i].name << '\n';
cout << donors[i].contribution << '\n';
}
}
if(!grandpatrons_exist){
cout << "None\n";
}
cout << "Here's the list of Patrons:\n";
for(int i = 0; 1 < amount; ++i){
if(donors[i].contribution < 10000){
cout << donors[i].name << '\n';
cout << donors[i].contribution << '\n';
}
}
delete[] donors;
return 0;
}
Now, an even better solution would be to use vectors instead of raw pointers and implement operator>> and operator<< which would greatly simplify
the reading and printing of the objects.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class Donor{
public:
Donor() noexcept: name(), contribution(0){}
friend istream& operator>>(istream& stream, Donor& donor){
switch(stream.peek()){
case EOF: return stream;
case '\n': stream.ignore();
}
getline(stream, donor.name);
stream >> donor.contribution;
return stream;
}
friend ostream& operator<<(ostream& stream, const Donor& donor){
stream << donor.name << ' ' << donor.contribution;
return stream;
}
const string& get_name() const noexcept{
return name;
}
const double& get_contribution() const noexcept{
return contribution;
}
private:
string name;
double contribution;
};
int main(){
cout << "Enter the filename: ";
string filename;
cin >> filename;
ifstream inFile(filename);
if(!inFile){
cout << "Could not open the file " << filename << '\n';
cout << "Program terminating.\n";
exit(EXIT_FAILURE);
}
int amount;
inFile >> amount;
vector<Donor> donors(amount);
//Read it as `for donor in donors`
for(Donor& donor : donors){
inFile >> donor;
}
//An STL function that takes a lambda as the thirs argument. You should read up on them if you haven't.
//I would prefer using this since it greatly improves readability.
//This isn't mandatory, your implementation of this part is good enough.
bool grandpatrons_exist = any_of(begin(donors), end(donors), [](const Donor& donor){ return donor.get_contribution() >= 10000; });
cout << "Here's the list of Grand Patrons:\n";
if(grandpatrons_exist){
for(const Donor& donor : donors){
if(donor.get_contribution() >= 10000){
cout << donor << '\n';
}
}
}
else{
cout << "None\n";
}
cout << "\nHere's the list of Patrons:\n";
for(const Donor& donor : donors){
if(donor.get_contribution() < 10000){
cout << donor << '\n';
}
}
return 0;
}
Some other great improvements would be:
Use partition to seperate great patrons from normal ones.
Use stream iterators to read the objects into the vector.
int main(){
cout << "Enter the filename: ";
string filename;
cin >> filename;
ifstream inFile(filename);
if(!inFile){
cout << "Could not open the file " << filename << '\n';
cout << "Program terminating.\n";
exit(EXIT_FAILURE);
}
//Ignore the first line completely
inFile.ignore(numeric_limits<streamsize>::max(), '\n');
//Calls `operator>>` internally
vector<Donor> donors(istream_iterator<Donor>{inFile}, istream_iterator<Donor>{});
auto first_grand_patron = partition(begin(donors), end(donors), [](const Donor& donor){ return donor.get_contribution() >= 10000; });
cout << "Here's the list of Grand Patrons:\n";
if(first_grand_patron == begin(donors)){
cout << "None!\n";
}
for(auto patron = begin(donors); patron != first_grand_patron; ++patron){
cout << *patron << '\n';
}
cout << "\nHere's the list of Patrons:\n";
for(auto patron = first_grand_patron; patron != end(donors); ++patron){
cout << *patron << '\n';
}
return 0;
}
Now some general tips:
Struct/Class names should start with a capital letter.
Stop Using std::endl.
No need to cin.clear(). Cin is only used once and never again.
Use member-initializer lists.
Optionally use ++i instead of i++ in for loops to get used to the correct way of incrementing a variable unless needed otherwise.
bool grandpatrons is too much of an abstract name for a flag.
donors is a subjectively better name than short for donor list.
I have 2 c++ code: one is for write data into a binary file, another is for read that file.
write.cpp code is as below:
#include <iostream>
#include <fstream>
using namespace std;
const int NAME_SIZE = 51;
struct Data
{
char name[NAME_SIZE];
int age;
};
int main()
{
Data person;
char again;
fstream people("people.db", ios::out | ios::binary);
do
{
cout << "Enter the following data about a "<< "person:\n";
cout << "Name: ";
cin.getline(person.name, NAME_SIZE);
cout << "Age: ";
cin >> person.age;
cin.ignore();
people.write(reinterpret_cast<char *>(&person),sizeof(person));
cout << "Do you want to enter another record? ";
cin >> again;
cin.ignore();
} while (again == 'Y' || again == 'y');
people.close();
return 0;
}
read.cpp code is as below:
#include <iostream>
#include <fstream>
using namespace std;
const int NAME_SIZE = 51;
struct Data
{
char name[NAME_SIZE];
int age;
};
int main()
{
Data person;
char again;
fstream people;
people.open("people.db", ios::in | ios::binary);
if (!people)
{
cout << "Error opening file. Program aborting.\n";
return 0;
}
cout << "Here are the people in the file:\n\n";
people.read(reinterpret_cast<char *>(&person),sizeof(person));
while (!people.eof())
{
cout << "Name: ";
cout << person.name << endl;
cout << "Age: ";
cout << person.age << endl;
cout << "\nPress the Enter key to see the next record.\n";
cin.get(again);
people.read(reinterpret_cast<char *>(&person),sizeof(person));
}
cout << "That's all the data in the file!\n";
people.close();
return 0;
}
Above mentioned codes work fine. The problem arises when I use string type members in the structure:
new write.cpp:
#include <iostream>
#include <fstream>
using namespace std;
struct Data
{
string name;
int age;
};
int main()
{
Data person;
char again;
fstream people("people.db", ios::out | ios::binary);
do
{
cout << "Enter the following data about a "<< "person:\n";
cout << "Name: ";
cin>>person.name;
cout << "Age: ";
cin >> person.age;
cin.ignore();
people.write(reinterpret_cast<char *>(&person),sizeof(person));
cout << "Do you want to enter another record? ";
cin >> again;
cin.ignore();
} while (again == 'Y' || again == 'y');
people.close();
return 0;
}
new read.cpp:
#include <iostream>
#include <fstream>
using namespace std;
struct Data
{
string name;
int age;
};
int main()
{
Data person;
char again;
fstream people;
people.open("people.db", ios::in | ios::binary);
if (!people)
{
cout << "Error opening file. Program aborting.\n";
return 0;
}
cout << "Here are the people in the file:\n\n";
people.read(reinterpret_cast<char *>(&person),sizeof(person));
while (!people.eof())
{
cout << "Name: ";
cout << person.name << endl;
cout << "Age: ";
cout << person.age << endl;
cout << "\nPress the Enter key to see the next record.\n";
cin.get(again);
people.read(reinterpret_cast<char *>(&person),sizeof(person));
}
cout << "That's all the data in the file!\n";
people.close();
return 0;
}
Now when I run read.cpp the program can't read string and the program crashes. I must use string as a member of the structure. How to solve this problem?
The only way that comes to mind is to write the following data separately:
Length of the string.
The array of characters of the string.
The age.
and read them separately.
Create functions to write/read an instance of Data such that they are aware of each other's implementation strategy.
std::ostream& write(std::ostream& out, Data const& data)
{
size_t len = data.name.size();
out.write(reinterpret_cast<char const*>(&len), sizeof(len));
out.write(data.name.c_str(), len);
out.write(reinterpret_cast<char const*>(&data.age));
return out;
}
std::istream& read(std::istream& in, Data& data)
{
size_t len;
in.read(reinterpret_cast<char*>(&len), sizeof(len));
char* name = new char[len+1];
in.read(name, len);
name[len] = '\0';
data.name = name;
delete [] name;
in.read(reinterpret_cast<char*>(&data.age));
return in;
}
and use them similarly to your first approach.
Instead of using
people.write(reinterpret_cast<char *>(&person),sizeof(person));
use
write(people, person);
Instead of using
people.read(reinterpret_cast<char *>(&person),sizeof(person));
use
read(people, person);
One problem is that sizeof(person.Name) does not give what you think it does. It always gives the same size (28 bytes in my case) not matter what characters you assign to your person.Name string. This is because of std::string contains at least:
a pointer to the actual string
other data structure to hold the available size and the size used
Therefore, you cannot call people.write(reinterpret_cast<char *>(&person),sizeof(person));. The content of your string is not located at &person (its located wherever the pointer in std::string is pointing to)
So, what happens when you do cout << person.name << endl; after reading it from your file? You've actually read the address (not the content) where person.name's string pointer was pointing to, when you wrote person to people.db. This is of course not a valid memory location, after reading it from your file, again.
The following code snippet could be helpful in your case. Instead of writing the length of the string, it is possible to use a delimiter and a pre-defined string length.
constexpr char delimiter = '\0';
constexpr uint32_t maxStringSize = 1024;
struct Data
{
string name;
int age;
};
When writing the file, place a delimiter after the string.
Let's say we have a Data structure {"John", 42} then we would write as follows:
std::ofstream outStream(filename, std::ios::binary);
outStream << structure.name << delimiter << structure.age;
outStream.close();
Reading the file is not the mirror of the write (unfortunately).
We'll use the std::ifstream::getline to read the string without knowing the size of it. (Error checking omitted)
std::ifstream istrm(filename, std::ios::binary);
Data dataRead;
// string input - use a buffer and look for the next delimiter
char* buf = new char[maxStringSize];
istrm.getline(buf, maxStringSize, delimiter);
dataRead.name = std::string(buf);
// the number input
istrm >> dataRead.age;
For inspiration how to read/write a vector of this struct you can check my repository.
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
using namespace std;
struct subscriberName
{
string first;
string last;
int custID;
};
struct address
{
string address2;
string city;
string state;
int zipcode;
};
struct date
{
string month;
int day;
int year;
};
struct renewal_information
{
int monthsLeft;
date da;
};
struct subscriberInfo
{
subscriberName si;
address ad;
renewal_information ri;
};
int main()
{
void OpenFileIn(ifstream& FileIn, string& FilenameIn);
void OpenFileOut(ofstream& FileOut, string& FilenameOut);
bool ProcessCustInfo(bool& truth, ifstream& FileIn);
void OutputCustInfo(ifstream& FileIn, ofstream& FileOut);
ifstream FileIn;
ofstream FileOut;
string FilenameIn;
string FilenameOut;
bool truth;
subscriberInfo si;
OpenFileIn(FileIn, FilenameIn);
OpenFileOut(FileOut, FilenameOut);
ProcessCustInfo(truth, FileIn);
OutputCustInfo(FileIn, FileOut);
return 0;
}
bool ProcessCustInfo(bool& truth, ifstream& FileIn, subscriberInfo& si)
{
getline(FileIn, si.sn.first, '\n'); //here
getline(FileIn, si.sn.last, '\n');
getline(FileIn, si.sn.custID, '\n');
getline(FileIn, si.ad.address2, '\n');
getline(FileIn, si.ad.city, '\n');
getline(FileIn, si.ad.state, '\n');
getline(FileIn, si.ad.zipcode, '\n');
getline(FileIn, si.ri.monthsLeft '\n'); //to here
}
void OutputCustInfo(ifstream& FileIn, ofstream& FileOut, subscriberInfo& si)
{
if(si.ri.monthsLeft=0) //here down to
{
FileOut << string(55,'*') << endl;
FileOut << si.sn.first << " " << si.sn.last << "(" << si.sn.custID << ")" << endl;
FileOut << sn.ad.address2 << endl;
FileOut << sn.ad.city << ", " << sn.ad.state <<sn.ad.zipcode << endl;
FileOut << "The last renewal notice was sent on " <<sn.ri.da.month << " " << sn.ri.da.day << ", " << sn.ri.da.year << endl; //here
FileOut << string(55,'*') << endl;
}
}
I can't figure out what is causing this error. It occurs in the first function where all the getline calls are. The compiler is specifically calling out the third, fifth, and last one, but I'm pretty sure there is something wrong with all of them.
You are passing a variable of type int to getline in:
getline(FileIn, si.sn.custID, '\n');
That's a problem.
Use:
std::string custID;
getline(FileIn, custID, '\n');
si.sn.custID = std::stoi(custID);
You have same problem with:
getline(FileIn, si.ad.zipcode, '\n');
and
getline(FileIn, si.ri.monthsLeft '\n');
Also, the line
if(si.ri.monthsLeft=0)
is wrong. I suspect it is a typo. You need to use == instead of =
if(si.ri.monthsLeft == 0)
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;