6

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.

Onato
  • 9,916
  • 5
  • 46
  • 54
Axeem
  • 670
  • 4
  • 16
  • 26
  • suggestions: write to a new file and move that over the original file + std::string has find and replace member-functions. – stefaanv Jan 17 '14 at 07:47
  • I just saw that you want to replace complete lines, so only my first suggestion is valid. The second was to replace part of lines. Inline replacement in files only works for replacement of the same size. – stefaanv Jan 17 '14 at 08:00

4 Answers4

9

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';
    }
}
JorenHeit
  • 3,877
  • 2
  • 22
  • 28
5

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;
    }
  }
} 
Avi Tevet
  • 778
  • 1
  • 7
  • 13
1
#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
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Sumeet
  • 119
  • 1
  • 7
0

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.

Abhishek Dutt
  • 1,308
  • 7
  • 14
  • 24