Deleting a line from c++ file by giving a word - c++

I have made a Quizlet code to save a word with its translation(in Russian) in csv file.
So, the 'add' and 'read' functions work perfectly but I have been trying to make the 'delete' function remove a line when I give a substring of that line.
update: I am trying to copy all the lines except the one that i wanna delete to a new file and then rename it.
but when the new file is created, it is empty!
ex: in the file, line 1: apple яблоко.
input: apple, and then the entire is being deleted.
here is my code: I just have a problem in void quizlet::DeleteWord()
#include <string>
#include <iostream>
#include <vector>
#include<fstream>
#include <sstream>
#include<cstdlib>
using namespace std;
class quizlet {
private:
std::string filename;
std::vector<std::string> lines;
public:
quizlet(std::string filename) : filename(filename) {}
void AddWord(std::string, std::string);
vector<string> ReadAllWords();
void DeleteWord();
};
void quizlet::AddWord(std::string word, std::string translation) {
cout << "Write a word and its translation separated by a space:" << std::endl;
cin >> word >> translation;
// file pointer
fstream fout;
// opens an existing csv file or creates a new file.
fout.open("words.txt",ios::out | ios::app);
// Insert the data to file
fout <<word<<" "<<translation<<endl;
std::cout << "Saved new card: " << word << "/" << translation << std::endl;
}
vector<string> quizlet::ReadAllWords() {
// File pointer
fstream fin;
// Open an existing file
fin.open("words.txt", ios::in);
// Read the Data from the file
// as String Vector
vector <string> rows;
string line, word, temp;
while (getline(fin, line)) {
cout << line << std::endl;
rows.push_back(line);
stringstream s(line);
}
return rows;
}
void quizlet::DeleteWord() {
string line;
fstream fin;
fstream fout;
fin.open("words.txt", ios::in);
fout.open("new.txt",ios::out | ios::app);
string token;
cin>>token;
vector <string> lines;
while (getline(fin, line)) {
if (line.find(token) != string::npos) {
cout << line << endl;
fin << line << endl;
cout<<"the line has been deleted!";
//remove (line);
}
}
fin.close();
fout.close();
remove("words.txt");
rename("new.txt", "words.txt");
cout << "\nChanges has Successfully been made...... Data Saved\n" << endl;
}
int main() {
auto Quizlet = quizlet("words.txt");
string word, translation;
while (true) {
std::string command;
std::cin >> command;
if (command == "add") {
Quizlet.AddWord(word, translation);
} else if (command == "read") {
Quizlet.ReadAllWords();
}
else if (command == "delete") {
Quizlet.DeleteWord();
}
else {
return 0;
}
}
}

Post-update edit:
My original answer now makes much more sense given what you are trying to do. You should read the whole file in at once, make any additions and deletions in-memory you want, then overwrite the original file with the whole, new, list.
Original answer:
Consider reading the file into memory via a std::map<std::string,std::wstring> instead of a std::vector<std::string> of lines in the file.
Using this approach, adding and deleting a word and its translation is simple.
Adding:
//if-guard only needed if you want to protect against overwriting already-existing words.
auto found_iter = cards.find(word);
if(found_iter == cards.end()) {
cards.insert_or_assign(word, translation);
}
Deleting:
auto found_iter = cards.find(word);
if(found_iter != cards.end()) {
cards.erase(found_iter);
}
Writing it back to the file is as simple as looping over the collection:
for(const auto& [word,translation] : cards) {
fout << word << ' ' << translation << '\n';
}
fout.close();

well, after trying for a long time.
I got this code and it works perfectly with no errors.
thank you all!
#include <string>
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include <cstdlib>
using namespace std;
class quizlet {
private:
std::string filename;
std::vector<std::string> lines;
public:
quizlet(std::string filename) : filename(filename) {}
void AddWord(std::string, std::string);
vector<string> ReadAllWords();
void DeleteWord(std::string);
};
void quizlet::AddWord(std::string word, std::string translation) {
cout << "Write a word and its translation separated by a space:" << std::endl;
cin >> word >> translation;
// file pointer
fstream fout;
// opens an existing csv file or creates a new file.
fout.open("words.txt",ios::out | ios::app);
// Insert the data to file
fout << word << " " << translation << endl;
std::cout << "Saved new card: " << word << "/" << translation << std::endl;
}
vector<string> quizlet::ReadAllWords() {
// File pointer
fstream fin;
// Open an existing file
fin.open("words.txt", ios::in);
// Read the Data from the file
// as String Vector
vector <string> rows;
string line, word, temp;
while (getline(fin, line)) {
cout << line << std::endl;
rows.push_back(line);
stringstream s(line);
}
return rows;
}
void quizlet::DeleteWord(string token) {
string line;
fstream fin;
fstream fout;
fin.open("words.txt", ios::in);
fout.open("new.txt",ios::out | ios::app);
cin >> token;
vector<string> lines;
while(getline(fin, line)) {
if(line.find(token) == string::npos) {
fout << line << endl;
}
}
fout.close();
fin.close();
remove("words.txt");
rename("new.txt", "words.txt");
cout << "\nChanges has Successfully been made...... Data Saved\n" << endl;
}
int main() {
auto Quizlet = quizlet("words.txt");
string word, translation, token;
while(true) {
std::string command;
std::cin >> command;
if(command == "add") {
Quizlet.AddWord(word, translation);
} else if(command == "read") {
Quizlet.ReadAllWords();
} else if(command == "delete") {
Quizlet.DeleteWord(token);
} else {
return 0;
}
}
}

Related

replacing string based on user input c++

i want to receive an input from user and search a file for that input. when i found a line that includes that specific word, i want to print it and get another input to change a part of that line based on second user input with third user input. (I'm writing a hospital management app and this is a part of project that patients and edit their document).
i completed 90 percent of the project but i don't know how to replace it. check out following code:
#include <iostream>
#include <stream>
#include <string.h>
#include <string>
using namespace std;
int main(){
string srch;
string line;
fstream Myfile;
string word, replacement, name;
int counter;
Myfile.open("Patientlist.txt", ios::in|ios::out);
cout << "\nEnter your Name: ";
cin.ignore();
getline(cin, srch);
if(Myfile.is_open())
{
while(getline(Myfile, line)){
if (line.find(srch) != string::npos){
cout << "\nYour details are: \n" << line << endl << "What do you want to change? *type it's word and then type the replacement!*" << endl;
cin >> word >> replacement;
}
// i want to change in here
}
}else
{
cout << "\nSearch Failed... Patient not found!" << endl;
}
Myfile.close();
}
for example my file contains this line ( David , ha , 2002 ) and user wants to change 2002 to 2003
You cannot replace the string directly in the file. You have to:
Write to a temporary file what you read & changed.
Rename the original one (or delete it if you are sure everything went fine).
Rename the temporary file to the original one.
Ideally, the rename part should be done in one step. For instance, you do not want to end up with no file because the original file was deleted but the temporary one was not renamed due to some error - see your OS documentation for this.
Here's an idea:
#include <iostream>
#include <fstream>
#include <string>
#include <cstdio>
using namespace std;
void replace(string& s, const string& old_str, const string& new_str)
{
for (size_t off = 0, found_idx = s.find(old_str, off); found_idx != string::npos; off += new_str.length(), found_idx = s.find(old_str, off))
s.replace(found_idx, old_str.length(), new_str);
}
int main()
{
const char* in_fn = "c:/temp/in.txt";
const char* bak_fn = "c:/temp/in.bak";
const char* tmp_fn = "c:/temp/tmp.txt";
const char* out_fn = "c:/temp/out.txt";
string old_str{ "2002" };
string new_str{ "2003" };
// read, rename, write
{
ifstream in{ in_fn };
if (!in)
return -1; // could not open
ofstream tmp{ tmp_fn };
if (!tmp)
return -2; // could not open
string line;
while (getline(in, line))
{
replace(line, old_str, new_str);
tmp << line << endl;
}
} // in & tmp are closed here
// this should be done in one step
{
remove(bak_fn);
rename(in_fn, bak_fn);
remove(out_fn);
rename(tmp_fn, in_fn);
remove(tmp_fn);
}
return 0;
}
One possible way:
Close the file after you read it into "line" variable, then:
std::replace(0, line.length(), "2002", "2003")
Then overwrite the old file.
Note that std::replace is different from string::replace!!
The header is supposed to be <fstream> rather than <stream>
you can't read and write to a file simultaneously so I have closed the file after reading before reopening the file for writing.
instead of updating text inside the file, your line can be updated and then written to file.
#include <iostream>
#include <fstream>
#include <string.h>
#include <string>
using namespace std;
int main(){
string srch;
string line, line2;
fstream Myfile;
string word, replacement, name;
int counter;
Myfile.open("Patientlist.txt", ios::in);
cout << "\nEnter your Name: ";
cin.ignore();
getline(cin, srch);
if(Myfile.is_open())
{
while(getline(Myfile, line)){
if (line.find(srch) != string::npos){
cout << "\nYour details are: \n" << line << endl << "What do you want to change? *type it's word and then type the replacement!*" << endl;
cin >> word >> replacement;
int index = line.find(word);
if (index != string::npos){
Myfile.close();
Myfile.open("Patientlist.txt", ios::out);
line.replace(index, word.length(), replacement);
Myfile.write(line.data(), line.size());
Myfile.close();
}
}
// i want to change in here
}
}else
{
cout << "\nSearch Failed... Patient not found!" << endl;
}
}

Is there a way to print individual words from a .txt file without leaving out lines?

#include <iostream>
#include <string>
#include <fstream>
using namespace std;
string readFileToString(string fileName) {
fstream file;
string word;
string returnMe;
returnMe.resize(200);
file.open(fileName.c_str());
while (file >> word) {
returnMe += word + " ";
}
file.close();
return returnMe;
}
int main() {
string fileName = "example.txt";
cout << readFileToString(fileName);
}
I have this code but I have several lines in my txt file and it completely ignores them.
If you want to print out all the words in the text file then you can use the following program:
#include <iostream>
#include <sstream>
#include <fstream>
int main()
{
std::ifstream inputFile("input.txt");
std::string word, line;
if(inputFile)
{
while(std::getline(inputFile, line)) //go line by line
{
//std::cout<<line<<std::endl; //this prints the line
std::istringstream ss(line);
while(ss >> word) //go word by word
{
std::cout << word << std::endl;
}
}
}
else
{
std::cout << "File cannot be opened" << std::endl;
}
return 0;
}
The output of the above program can be seen here.

Getting more than one line from .txt file C++

I want to take more than one line from the data.txt file. I am able to take only the first one. I tried using while loop but it seems that I don't know how to use it in this case.
Edited with while loop:
#include <iostream>
#include <fstream>
using namespace std;
int zapis()
{
fstream file;
string text;
file.open("data.txt", ios::app);
cout << "Type in text that you would like to store: ";
getline(cin, text);
file << text << endl;
file.close();
return 0;
}
int odczyt()
{
fstream file;
string line;
int nr_lini = 1;
file.open("data.txt", ios::in);
if(file.good()==false)
{
cout << "Error occured!";
}
else
{
while(getline(file, line))
{
getline(file, line);
cout << line;
}
}
file.close();
return 0;
}
int main()
{
zapis();
odczyt();
return 0;
}
Why call getline twice in your loop? Also pay attention to the semi-colons
while(getline(file, line));
^
What do you think the semi-colon there does?
This is correct
while (getline(file, line))
{
cout << line;
}
Your code is correct, just loop through the file. Also, you could make the function void, as it always returns 0, with you not doing anything with the return value.
void odczyt(){
fstream file;
string line;
file.open("data.txt", ios::in);
if(!file.good())
{
cout << "Error occured!";
}
else
{
while(getline(file, line);) { // while text file still has lines, you write the line and read next
cout << line;
}
}
file.close();
}

C++ copying another file

i was wondering how to use c++ ifstream/ofstream to copy a file and save it as another name.
this is as far as i got. I know how to get the file, its just that i don't know how to copy that file and save it as a different name.
#include<iostream>
#include<fstream>
#include<string>
namespace std;
int main()
{
ofstream
ifstream
cout << "enter your file you want to copy"<< endl;
cin >> input_file_name;
in_file.open(input_file_name);
if (!in_file)
{
cout <<" there is no such file"<<endl;
return 0;
}
cout <<" enter the name you want to save this copy file"<<endl;
cin >> output_file_name;
out_file.open(output_file_name);
if (!out.file)
{
cout<<"file is not available"<<endl;
return 0;
}
in_file.close();
out_file.close();
return 0;
}
rdbuf with overloaded << is standard way to go.
ifstream src;
ofstream dst;
src.open("from", ios::in | ios::binary);
dst.open("toto", ios::out | ios::binary);
dst << src.rdbuf();
src.close();
dst.close();
Copy a file and save it on another file:
#include <fstream>
#include <iostream>
#include <string>
int main(int arc, char* argv[]) {
std::ifstream file1(argv[1]);
std::ofstream file2(argv[2]);
std::string line;
if (file1.good() && file2.good()) {
while (getline(file1, line)) {
file2 << line;
file2 << '\n';
}
}
file1.close();
file2.close();
}
Basically you want to read a character at a time and write said character to the output stream. There's a get() overload which accepts a streambuf output variable that would work. You could also use the example on cplusplus.com rdbuf documentation.
http://www.cplusplus.com/reference/fstream/ofstream/rdbuf/
This code below should give you a sense of what you want to do.
There are few things you should keep in mind, for example:
is the path of the file giving to read is valid?
or do you want to save the data from an output file if that file exists, before pushing new data?.
You could test this code by just creating a file into your desktop or any location, just change the filePath and destinationPath variables then run the code. (c++ 11)
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
vector<string> readFromFile(const char *filePath) {
vector<string> container;
ifstream obj(filePath); // automatically our file would be open
if (obj.is_open()) { // we check anyways
string line = "";
while(getline(obj, line)) {
if (!line.empty()) // prevent us to insert empty line into our vector
container.push_back(line);
}
obj.close(); // close after we finish reading to avoid corruption
}
return container;
}
bool pipingToDestination(vector<string>data, const char *filePath) {
std::filebuf fb; fb.open(filePath,std::ios::out); // open the file
ostream obj(&fb);
if (!data.empty() && fb.is_open()) { // make sure we have some data && the file file is open to write
for (string x: data) { // c++11
obj << x << endl;
}
fb.close();
return true;
}
return false;
}
int main() {
string filePath = "/Users/lamar/Desktop/testFile.txt";
vector<string> data = readFromFile(filePath.c_str());
cout << "File has passed data into container ... \n";
for(string x: data) {
cout << x << endl;
}
cout << "Creating destination file \n";
string destinationPath = "/Users/lamar/Desktop/destFile.txt";
cout << "has piped data into file " << boolalpha << pipingToDestination(data, destinationPath.c_str());
return 0;
}
This is not the only way to do this, but this code should put you on a direction

How to tell your program which file you want to read C++

#include <iostream>
#include <string>
#include <fstream>
using namespace std;
void read();
int main() {
read();
return 0;
}
void read () {
string file("");
string nameOfFile("");
cin >> nameOfFile;
ifstream in (nameOfFile);
while ( !in.eof() ) {
getline(in, file);
cout << file;
cout << endl;
}
cout << file;
in.close();
}
How come this isn't working, I'm trying to make it so i can type in which file i want to read?
I'm really new to C++, sorry if this is an obvious fix.
You have to change
ifstream in (nameOfFile);
with
ifstream in (nameOfFile.c_str());
because the default constructor for ifstream does not accept a std::string as an argument, it needs a char *. Hence, use the function std::string::c_str() to convert a std::string into a char *.
A little feedback:
void read () {
string file(""); // you don't need the ("") bit; empty by default,
// and "file" is a terrible choice of identifier as
// it sounds more like an ifstream than a string
// used to hold one line from the file.
// I tend to use "string line;" for this.
string nameOfFile(""); // ditto
cin >> nameOfFile; // you should test for success of input, like this:
// if (!cin >> nameOfFile) {
// std::cerr << "error reading filename from stdin\n";
// exit(1);
// }
ifstream in (nameOfFile); // test for success getting file open like this:
// if (ifstream in(nameofFile))
// {
while ( !in.eof() ) { // NEVER check eof before attempting input, instead:
getline(in, file); // while (getline(in, file))
cout << file; // cout << file << endl; // can "chain"
cout << endl; // }
// else
// std::cerr << "couldn't open " << nameOfFile
// << '\n';
} // no need for extra cout nor explicit close, as
cout << file; // the ifstream destructor closes anyway.
in.close();
}
You need to open the ifstream usign in.open(), and hendle the case where file does not exist as well. here is the function:
void read() {
string file("");
string fileContent = "";
string nameOfFile("");
cin >> nameOfFile;
ifstream in(nameOfFile.c_str());
in.open(nameOfFile, ios::in);
if (in){
while (!in.eof()) {
getline(in, file);
fileContent += file;
}
cout << fileContent;
in.close();
}
else {
cout << "Could not open file.";
}
}