Deleting specific line from file - c++

These are the contents of my example file:
abcdefg hijk lmnopqrstAB CSTAKLJSKDJD KSA FIND ME akjsdkjhwjkjhasfkajbsdh ADHKJAHSKDJH
I need to find and delete the 'FIND ME' inside of the file so the output would look like this:
abcdefg hijk lmnopqrstAB CSTAKLJSKDJD KSA akjsdkjhwjkjhasfkajbsdh ADHKJAHSKDJH
I have tried the following method of doing getline and then writing all of the contents except the FIND ME into a temporary file and then rename the temporary file back.
string deleteline;
string line;
ifstream fin;
fin.open("example.txt");
ofstream temp;
temp.open("temp.txt");
cout << "Which line do you want to remove? ";
cin >> deleteline;
while (getline(fin,line))
{
if (line != deleteline)
{
temp << line << endl;
}
}
temp.close();
fin.close();
remove("example.txt");
rename("temp.txt","example.txt");
but it doesn't work.
Just as a side note: the file has NO newline/linefeeds. So the file contents are all written in 1 line.
EDIT:
FIXED CODE:
while (getline(fin,line))
{
line.replace(line.find(deleteline),deleteline.length(),"");
temp << line << endl;
}
This gets me the results I expected. Thank you everyone for helping!

In case anyone would like it I have converted Venraey's useful code into a function:
#include <iostream>
#include <fstream>
void eraseFileLine(std::string path, std::string eraseLine) {
std::string line;
std::ifstream fin;
fin.open(path);
// contents of path must be copied to a temp file then
// renamed back to the path file
std::ofstream temp;
temp.open("temp.txt");
while (getline(fin, line)) {
// write all lines to temp other than the line marked for erasing
if (line != eraseLine)
temp << line << std::endl;
}
temp.close();
fin.close();
// required conversion for remove and rename functions
const char * p = path.c_str();
remove(p);
rename("temp.txt", p);
}

Try this:
line.replace(line.find(deleteline),deleteline.length(),"");

I'd like to clarify something. Although the answer provided by gmas80 could work, for me, it didn't. I had to modify it somewhat, and here's what I ended up with:
position = line.find(deleteLine);
if (position != string::npos) {
line.replace(line.find(deleteLine), deleteLine.length(), "");
}
Another thing that didn't satisfy me was that it left blank lines in the code. So I wrote another thing to delete the blank lines:
if (!line.empty()) {
temp << line << endl;
}

Related

I am getting several errors in this section of my code in which I am trying to turn the output into capital letters

{
const char* fname = "myfile"; //or string fname ("str.txt") in C++11
string input; //our first look at the C++ string object
fstream myfile; //construct fstream object for file i/o
openfile(myfile, fname, ios_base::out); //open file for output (current contents lost)
std::transform(myfile.open(), myfile.end(), myfile.open(), ::toupper);
while (cout << "Enter a line ('q' to quit): " && getline(cin, input))
{
if (input == "q")
break;
else //exit while loop
myfile << input << endl; //pipe string we read file add new line character
}
myfile.close(); //close our file
std::transform(myfile.open(), myfile.end(), myfile.open(), ::toupper);
openfile(myfile, fname, ios_base::in); //reopen it for input
cout << "\nHere's whats in " << fname << ":\n";
while (getline(myfile, input)) //get and print all the lines
cout << input << endl;
system("pause");
}
Severity Code Description Project File Line Suppression State
Error (active) E0304 no instance of overloaded function "std::basic_fstream<_Elem, _Traits>::open [with _Elem=char, _Traits=std::char_traits<char>]" matches the argument list fileio2 C:\Users\burnsk\source\repos\Hello\fileio2\fileio2.cpp 14
Severity Code Description Project File Line Suppression State
Error (active) E0109 expression preceding parentheses of apparent call must have (pointer-to-) function type fileio2 C:\Users\burnsk\source\repos\Hello\fileio2\fileio2.cpp 14
std::transform(myfile.open()
That's not going to work. std::transform expects an input iterator range, typically some begin/end range. std::fstream::open doesn't return an iterator.
You probably want to look at std::istream_iterator<char>.
We'll do a quick code review of what you've posted. I've removed most of your comments, and we'll actually use that as our first critique. The comments don't help readability at all. You're just restating the line of code, which isn't a great comment. Comments that explain 'why' or fill in the information gaps that the code alone cannot explain are much better.
// Missing includes and main()
// This does not qualify as a Minimal, Reproducible Example
// Specifically, it's not reproducible, as it cannot be copy/pasted
// and ran by the people you want to get help from.
// https://stackoverflow.com/help/minimal-reproducible-example
{
const char* fname = "myfile"; // Hard-coded file name is meh, C-string also
string input; // Prefer this EVERYWHERE
fstream myfile;
openfile(myfile, fname, ios_base::out); // No explanation of this function
// It's not standard, you should
// have posted its code.
// Bad syntax, as explained. Refer to the documentation
// https://en.cppreference.com/w/cpp/algorithm/transform
std::transform(myfile.open(), myfile.end(), myfile.open(), ::toupper);
// Clever, but the user likely doesn't need to be prompted before
// every line. Instead, you could have checked for the end condition.
while (cout << "Enter a line ('q' to quit): " && getline(cin, input))
{
if (input == "q")
break; // This is the line that exits the loop
else //exit while loop
myfile << input << endl; // Premature write
}
myfile.close();
// See above about transform syntax being bad. But why write data
// you don't want, close the file, re-open the file, try to
// re-write the data, and close the file again?
std::transform(myfile.open(), myfile.end(), myfile.open(), ::toupper);
openfile(myfile, fname, ios_base::in); //reopen it for input
cout << "\nHere's whats in " << fname << ":\n";
while (getline(myfile, input)) //get and print all the lines
cout << input << endl;
system("pause");
}
Since you are reading the strings in, and not caring about the original contents, why not manipulate the string to look the way you want, and then write it to the file. It's a lot simpler.
My code below does that, and uses a few other tricks to avoid copy/pasta.
The biggest change is that the user is only told what to do once, and the while() loop Boolean expression grabs the line and ensures it's not the quit condition.
The string is then run through std::transform() and fully capitalized. And then it is written to the file. This writes the data we want one time, instead of writing a bunch of bad data and then doubling back and trying to fix it.
For printing the contents of the file to the screen, we create a new class that holds a string and changes how it can be read in, essentially reading an entire line at a time instead of a word. This is not necessary, but like I said, I put some stuff in to avoid a straight copy/paste/submit situation.
#include <algorithm>
#include <cctype>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
namespace detail {
class Line {
std::string m_line;
public:
friend std::istream& operator>>(std::istream& sin, Line& line) {
std::getline(sin, line.m_line);
return sin;
}
operator std::string() const { return m_line; }
};
} // namespace detail
int main(int argc, char* argv[]) {
if (argc != 2) return 1;
std::ofstream fout(argv[1]);
if (!fout) {
std::cerr << "Error opening file for writing.\n";
return 2;
}
std::cout << "Type lines. Type \"q\" on its own line to quit.\n";
std::string line;
while (std::getline(std::cin, line) && line != "q") {
std::transform(line.begin(), line.end(), line.begin(),
[](const auto& c) { return std::toupper(c); });
fout << line << '\n';
}
fout.close();
std::ifstream fin(argv[1]);
if (!fin) {
std::cerr << "Error opening file for reading.\n";
return 3;
}
std::copy(std::istream_iterator<detail::Line>(fin),
std::istream_iterator<detail::Line>(),
std::ostream_iterator<std::string>(std::cout, "\n"));
fin.close();
}
Output:
❯ ./a.out text.txt
Type lines. Type "q" on its own line to quit.
You'll be back, time will tell
You'll remember that I served you well
Oceans rise, empires fall
We have seen each other through it all
And when push comes to shove
I will send a fully armed battalion to remind you of my love!
q
YOU'LL BE BACK, TIME WILL TELL
YOU'LL REMEMBER THAT I SERVED YOU WELL
OCEANS RISE, EMPIRES FALL
WE HAVE SEEN EACH OTHER THROUGH IT ALL
AND WHEN PUSH COMES TO SHOVE
I WILL SEND A FULLY ARMED BATTALION TO REMIND YOU OF MY LOVE!

C++ line justification with I/O

I am creating a program that justifies a paragraph to ensure that each line has a length of 75 char. I have created functions that will insert spaces and create these desired lengths as needed, but I am having problems reading a text file and trying to break it down line by line. Each line provided is less than the 75 char limit, and my functions do properly work when it is given only a line. But I do not know how to read line by line, manipulate it, and then write to my new .txt file. When I output this to the new text file, I am greeted by a justified line of text, not text that is in a paragraph block!
I have tried to create an if else loop that would only run when the string.length() is less than 75 char, and would create a new line when false, but I do not know how to create this new line in the program
string myString;
string line("\n");
while (getline(inFile, myString))
{
cout << myString << endl;
puncLoop(myString);
spaceLoop(myString);
}
}
In Order to output the file with new line you can use "\n".
#include <iostream>
#include <string>
#include <fstream>
int main() {
//in file object
std::ifstream inFile("example.txt");
//out file object
std::ofstream outFile ("example2.txt", std::ios_base::out | std::ios_base::trunc );
//Checking if file exist
if( inFile && outFile )
{
//temp valarable to store each line
std::string mystring;
//Loop through each line
while (getline(inFile, mystring))
{
//... Call Your Business Logic functions here, ( make use of pass by refernce or return to get back the string )
outFile << mystring.c_str() << "\n";
}
//closing file after completing
inFile.close();
outFile.close();
}
else
{
std::cout << "Could not open File to read or write"<<std::endl;
}
return 0;
}

How can I label the lines of an existing file?

Lets say I have a text file containing something like:
Four
score
and
seven
years
ago
...
I want to be able to label these lines so that after the program runs, the file looks like:
1.Four
2.score
3.and
4.seven
5.years
6.ago
...
I've prepared a solution; however, I find it to be heavy weight and it has a problem of labeling one past the last line...
std::string file = "set_test - Copy.txt";
std::ifstream in_test{file};
std::vector<std::string> lines;
while(in_test) {
std::string temp;
getline(in_test, temp);
lines.push_back(temp);
}
in_test.close();
std::ofstream out_test{file};
for(unsigned int i = 0; i < lines.size(); ++i) {
out_test << i+1 << '.' << lines[i] << '\n';
}
On top of being heavy-weight, this solution also labels the line beyond the last line of text.
Does anyone have a better solution to this problem?
The cause of your problem is this structure
while (stream is good)
read from stream
do something
as it will read too much. (See this Q&A for explanation.)
What's happening is that the very last getline, the one that actually reaches the end of the file, will fail and leave temp empty.
Then you add that empty line to your lines.
The "canonical" stream-reading loop structure is
while (attempt to read)
do something with the result
in your case,
std::string temp;
while (getline(in_test, temp)) {
lines.push_back(temp);
}
If you write to a different file you don't need to store anything except the last line; you can write each line immediately.
If you want to replace the original, you can replace the old with the new afterwards.
Something like this:
std::ifstream in_test{"set_test - Copy.txt";}
std::ofstream out_test{"set_test - Numbered.txt"};
if (!in_test || !out_test) {
std::cerr << "There was an error in the opening of the files.\n";
return;
}
int i = 1;
std::string line;
while (getline(in_test, line) && out_test << i << '.' << line << '\n') {
i++;
}

After while loop exits, contents of the string are being deleted?

Hey everyone this is my first post so if I make any mistakes, such as not enough info etc, please let me know so I do not make them again.
So my issue is I need to take the contents of a file and then input them into a string, which I have working. However after the while loop ends if I try to use that string outside the while loop and manipulate the contents the string. The string is blank and there seems to be no contents. I determined this by using std::cout lines. I believe this to be a scope issue but I am not sure how to fix it. Below is the code pertaining to the question, any tips or help would be greatly appreciated!
std::string str;
std::ifstream file;
while(!file.eof()){
getline(file, str);
std::cout << str << "";
}
file.close();
std::cout << str << "";
std::map<std::string, int> map;
for(int i = 0; i < str.length(); ++i){
std::string sub = str.substr(i, k);
std::cout << sub << std::endl;
map.insert(make_pair(sub, 1));
}
std::cout << "" << std::endl;
Also, I am trying to chop the string up into size k which is a variable defined in a different part of the code, so I used the substr method in C++, and I believe this is working because when I put it in the while loop I can print out the contents of the file but the format is off and I think that is because of the nature of how the while loop runs, but I am not sure, please correct me if I am wrong or have any misconceptions.
Wouldn't it be easier to store the text file into a std::vector and then choose what sentence you'd want to manipulate?
Example:
int main()
{
std::string str;
std::ifstream file{ "file.txt" };
std::vector<std::string> vec;
// Store text file in vector
while (std::getline(file, str)) {
vec.emplace_back(str);
}
// Print out line 2:
std::cout << vec.at(1) << '\n';
// Reverse line 2 and print:
std::string line2 { vec.at(1) };
std::reverse(begin(line2), end(line2));
std::cout << line2 << '\n';
}
You are only storing one line at a time with getline(file, str);. My guess is that the last line of your file is blank, so the last value stored to str is blank.
You can concatenate instead of overwriting:
std::string temp;
std::string str;
std::ifstream file;
while(!file.eof()){
getline(file, temp);
std::cout << str << "";
str = str + temp;
}
Alternatively, add #include <fstream> and use:
std::ifstream inputStream("myfile.txt");
std::string str((std::istreambuf_iterator<char>(inputStream),
(std::istreambuf_iterator<char>()));

Finding different strings in two files - C++

I'm trying to export all lines from second file that aren't in the first one. The order of the lines doesn't matters, I just want to find ones that aren't in the first file already and save them to difference.txt.
Example:
firstfile.txt
This is first line
This is second line
This is third line
secondfile.txt
This is first line
This is some line
This is third line
Now compare them...
difference.txt
This is some line
This is what I came up so far. I know I need to loop through all lines in the second file and compare each of that line with each line of the first file. It's not making any sense to me why it isn't working
void compfiles()
{
std::string diff;
std::cout << "-------- STARTING TO COMPARE FILES --------\n";
ifstream file2;
file2.open("C:\\\\firstfile.txt",ios::binary);
//---------- compare two files line by line ------------------
std::string str;
int j = 0;
while(!file2.eof())
{
getline(file2, str);
if(!CheckWord(str))
{
cout << "appending";
diff.append(str);
diff.append("\n");
}
j++;
}
ofstream myfile;
myfile.open ("C:\\\\difference.txt");
myfile << diff;
myfile.close();
}
bool CheckWord(std::string search)
{
ifstream file;
int matches = 0;
int c = 0;
file.open("C:\\\\secondfile.txt",ios::binary);
std::string stringf;
while(!file.eof())
{
getline(file, stringf);
if(strcmp(stringf.c_str(), search.c_str()))
{
matches += 1;
}
c++;
}
if(matches == 0)
{
return false;
}
else
{
return true;
}
}
Any help would be appreciated. Thanks for reading this block of text.
This code doesn't do what you think it does:
if (strcmp(stringf.c_str(), search.c_str()))
{
matches += 1;
}
strcmp() returns 0 when the strings are equal, but your code will not increment
matches in that case.
Here is a simple but much more effective and idiomatic solution using std::set:
std::ifstream file1("firstfile.txt");
std::set<std::string> str_in_file1;
std::string s;
while (std::getline(file1, s)) {
str_in_file1.insert(s);
}
file1.close();
std::ifstream file2("secondfile.txt");
std::ofstream file_diff("diff.txt");
while (std::getline(file2, s)) {
if (str_in_file1.find(s) == str_in_file1.end()) {
file_diff << s << std::endl;
}
}
file2.close();
file_diff.close();
Also, you might want to use a tool called diff. It does exactly what you are trying to do.
If you want to do it manually then it sounds like you don't need a c++ program but you can do this from the command line using grep.
grep -vxFf firstfile.txt secondfile.txt > difference.txt