Common File Tasks -- Search and Replace, and Append

A class to do search and replace functions within a file and add a line to a file.

Environment: MFC Visual C++ (6.0)

After re-implementing certain file functions a few times, I thought it would be worthwhile to make a class that would do some common tasks. This class basically does two things:

  1. Replace: Searches the specified file, replacing all occurences of the specified search string with the specified replacement string. An optional parameter is case-sensitivity. The return value is the number of replacements made.
  2. InsertLineIntoFile: Adds the specified entry to the specified file. Optional paramters are case-sensitivity and if the string should be added only if the entry does not already exist or not. The return value is non-zero if the line was added.

The class is really pretty simple. The code should be relatively easy to understand. I do not combine five statements into one and I try to use descriptive variable names.

An emphasis was placed on readability and functionality versus efficiency.

Extensive use was made of the CString functions.

To implement the SnR (Search and Replace) class, you just add SnR.cpp and SnR.h to your project and add #include "SnR.h" to your source code file.

A sample program/project is provided to demonstrate the use of the class.

I have put lots of comments in the code, so this is the end of the commentary. The .h and .cpp file are shown here and are available for download at the bottom, either by themselves or in the sample project.

Here is SnR.h:

// SnR (Search and Replace Class) written by James Moody
// Functions:
// Replace:  Replacing all occurences of a string in a file
//    case sensitive or not
//    returns the number of changes made
// DoLineReplacement:  Replacing all occurences of a sub-string 
//    in a string
//    case sensitive or not
//    returns the number of changes made
//    Was created to support the Replace Function but could be
//      used on its own
//    Takes a pointer to the string to be modified
//    InsertLineIntoFile
//      Targeted toward updating configuration 
//      files where line entries
//      should be added if they do not already exist
//      case sensitive or not.

class SnR
{
public:
  int Replace( CString TheFile,
               CString SearchString, 
               CString ReplaceString,
               int iCheckCase = 0);
  int DoLineReplacement(CString *LineString, 
                        CString SearchString,
                        CString ReplaceString,
                        int iCheckCase = 0 );
  int InsertLineIntoFile(CString TheFile,
                         CString InsertLine, 
    int iOnlyIfNotThere = 1, int iCheckCase=0);
private:

  char c;
  CString SearchTemp;
  CString ReplaceTemp;
  CString LineStringTemp;
  int iSearchToCompare;
  int iReturn;
  int iStringStart;
  int iRightCharacters;;
  int iLengthSearch;
  CString TempFile;
  FILE* pSearchFile;
  FILE* pTempFile;
  CString LineFromFile;
  CString LineToFile;
  CString RightPortion;

};

Here is SnR.cpp:

#include "stdafx.h"
#include "SnR.h"

// Class Name......: SandR
// Desription......: Search and Replace in a file, and add to a file
// Author, email, date....: James Moody james_moody@yahoo.com
//                          28 May 2002
// Public Member Functions (Methods):
// Replace	Does a search and replace on the contents 
//    of a file.
// Has a parameter to specify case-sensitive or not.
// InsertLineIntoFile	Adds the string to the file
//    Has a parameter to specify case-sensitive or not.
//    Has a parameter to specify if the line will be added 
//    if it already exists.
// DoLineReplacement	Is called by Replace, so it could be a 
//    private function, but 
//    could be useful by itself.  Within a string, 
//    replaces every occurence of the search string
//    with the replace string.


int SnR::DoLineReplacement(CString* LineString, 
                           CString SearchString, 
                           CString ReplaceString,
                           int iCheckCase)
{
iLengthSearch = SearchString.GetLength();
int iReturn2=0;  // the return value
SearchTemp = SearchString;  
ReplaceTemp =  ReplaceString;
LineStringTemp = *LineString;
//  If case insensitive, make all upper case before comparing
//  Use a temp string for comparing and make changes 
//    to the original string
if( ! iCheckCase)
{
SearchTemp.MakeUpper();
// ReplaceTemp.MakeUpper();
LineStringTemp.MakeUpper();

}

// will do the while loop until no more matches with the
// search string are found
// iStringStart (if not -1) will hold the location where 
// the matching string starts

while( (iStringStart= LineStringTemp.Find(SearchTemp)) != -1)
    {
    LineToFile = LineString->Left(iStringStart);
    // now LineToFile has everything up to where 
    //the search string starts
    LineToFile += ReplaceString;
    // now LineToFile has the replace string inserted
    iRightCharacters = LineString->GetLength() - 
      iStringStart - iLengthSearch;
    RightPortion = LineString->Right(iRightCharacters);
    LineToFile += RightPortion; 
  // now LineToFile has the string with the first 
    // occurence replaced
    *LineString = LineToFile;
  // now LineString has the string with the first occurence replaced
    LineStringTemp = *LineString;
    iReturn2++;
//  If case insensitive, make all upper case before comparing
//  Use a temp string for comparing and make changes 
//    to the original string
      if(! iCheckCase)
      {

      LineStringTemp.MakeUpper();
      } // if(iCheckCase)

    } // while (iStringStart= LineFromFile....
return iReturn2;
}


// Replace
// Replaces in 'TheFile' each occurrence of 'ReplaceString' 
//      with 'SearchString'
// iCheckCase, if Non-Zero makes the determination case sensitive 
//      and defaults to 0
int SnR::Replace( CString TheFile,
                  CString SearchString, 
                  CString ReplaceString,
                  int iCheckCase)
{
  iReturn=0;
  iStringStart = 0;
  iRightCharacters = 0;;
  iLengthSearch = SearchString.GetLength();
  TempFile = "tempSnr.txt";
  pSearchFile = 0;
  pTempFile = 0;
  LineFromFile = "";
  LineToFile = "";
  RightPortion = "";

  if(iLengthSearch < 1 )
      return 0;


  // going to open the search file
  if (pSearchFile =fopen(TheFile,"r"))
  {
  // going to open the temp file
  if(pTempFile = fopen(TempFile,"w"))
    {
  while ( (c=getc(pSearchFile) )!= EOF)  // filling the 
    //string with a line from the file.
    {
    LineFromFile += (CString) c;
    if((c != 10) && (c !=13) )
    {

    }
    else
  {  // found a newline or carriage return character
     // so now analyze the line
     // call DoLineReplacement on the newly aquired line
  iReturn += DoLineReplacement(&LineFromFile,
                               SearchString,
                               ReplaceString,
                               iCheckCase);

  LineToFile = LineFromFile;
  // print the possibly modified line to the temporary file
  fprintf(pTempFile,LineToFile);
  LineFromFile = "";
    }// if((c != 10) && (c !=13) )

  } //while (c=getc(TheFile) != EOF)

  // in case the last line did not have a cr or ln will 
  //analyze the line
  iReturn += DoLineReplacement(&LineFromFile, 
                               SearchString, 
                               ReplaceString,
                               iCheckCase);

    LineToFile = LineFromFile;
    fprintf(pTempFile,LineToFile);
    LineFromFile = "";
    // done dealing with the last line



  fclose(pTempFile);
  } //if(pTempFile = fopen(TempFile,"w"))
  else
  {

  } // else of if(pTempFile = fopen(TempFile,"w"))
  fclose(pSearchFile);
  }  //if (pSearchFile =fopen(TheFile,"r"))
  else
  {
  AfxMessageBox("Unable to open the file.");
  } //  else of if (pSearchFile =fopen(TheFile,"r"))


  if (iReturn)
    {  //  If any modifications were made
  // Now we will copy the newly created tempfile that 
  // has the modifications back to 
  // the original file, manually
  // It's true there is a CFile class member function 
  // called rename. We could have used that, but used this 
  // general method when creating the file anyway
  // so there should be no problem using this method 
  // to rename the file back
  if(pTempFile = fopen(TempFile,"r"))
  {
  if (pSearchFile =fopen(TheFile,"w"))
  {
  while ( (c=getc(pTempFile) )!= EOF)
    {
    putc(c,pSearchFile);
    }// while ( (c=getc(pSearchFile) )!= EOF)
  fclose(pSearchFile);
  } // if (pSearchFile =fopen(TheFile,"w"))
  fclose(pTempFile);	
  } // if(pTempFile = fopen(TempFile,"r"))
} // if (iReturn)
// deleting the temporary file that had the changes
DeleteFile(TempFile);	
return iReturn;

}  // BOOL SnR::Replace(CString TheFile, CString SearchString, 
    //CString ReplaceString)


//  InsertLineIntoFile
//  This Function works on a 'line' basis.
//  It inserts the line in the end of the file
//  The Parameter iOnlyIfNotThere, if Non-Zero will only add 
//    the line if it was not found in the file
//  The Parameter iCheckCase, if Non-Zero will make the 
//     determination
//  case sensitive
int SnR::InsertLineIntoFile(CString TheFile, CString InsertLine, 
  int iOnlyIfNotThere, int iCheckCase)
{
  iReturn=0;
  CString InsertLineTemp = InsertLine;

  int iFoundLine=0;
  //  If case insensitive, make all upper case before comparing
  //  Use a temp string for comparing and make changes to
  //  the original string
  if( ! iCheckCase) 
  {
    InsertLineTemp.MakeUpper();
  }

  LineFromFile = "";
  if(iOnlyIfNotThere) // need to find out if the string exists 
    //in the file if the parameter is 'on'
    if (pSearchFile =fopen(TheFile,"r"))
    {

    while ( (c=getc(pSearchFile) )!= EOF)
    {
    LineFromFile += (CString) c;
    if((c != 10) && (c !=13) )
    {
    }
    else
    {
    if( ! iCheckCase)
    {
      LineFromFile.MakeUpper();

    }

  if(InsertLineTemp == LineFromFile)
    {
    iFoundLine=1;
    } // if(InsertLine == LineFromFile)
  // Maybe a newline or whitespace prevented a 
  // match so trim those and check again
  LineFromFile.TrimRight("\n");
  LineFromFile.TrimRight();
  if(InsertLineTemp == LineFromFile)
    {
    iFoundLine=1;
    } // if(InsertLine == LineFromFile)


    LineFromFile = "";
    }// if((c != 10) && (c !=13) )

  } //while (c=getc(TheFile) != EOF)

// in case the last line did not have a cr or 
// ln will analyze the line
  if( ! iCheckCase)
  {
  LineFromFile.MakeUpper();
  }


  if(InsertLineTemp == LineFromFile)
    {
    iFoundLine=1;
    } // if(InsertLine == LineFromFile)
  // Maybe a newline or whitespace prevented a match 
  // so trim those and check again
  LineFromFile.TrimRight("\n");
  LineFromFile.TrimRight();
  if(InsertLineTemp == LineFromFile)
    {
    iFoundLine=1;
    } // if(InsertLine == LineFromFile)

  LineFromFile = "";
// done dealing with the last line

fclose(pSearchFile);

}  //if (pSearchFile =fopen(TheFile,"r"))
else
{
AfxMessageBox("Unable to open the file.");
} //  else of if (pSearchFile =fopen(TheFile,"r"))


// now we will add the line if it was not found or if we are 
// supposed to add it either way
if( (! iFoundLine ) || ( ! iOnlyIfNotThere) )
  {
  if (pSearchFile =fopen(TheFile,"a"))
  {
  fprintf(pSearchFile,"\n");
  fprintf(pSearchFile,InsertLine);
  fprintf(pSearchFile,"\n");
  fclose(pSearchFile);
  iReturn=1;
  } // if (pSearchFile =fopen(TheFile,"r"))

} // if( (! iFoundLine ) || ( ! iOnlyIfNotThere) )


return iReturn;
}

Downloads

Download demo project - SnR_demo.zip - 16 Kb
Download source -SnR_src.zip - 3 Kb


Comments

  • Any thoughts.......???

    Posted by Legacy on 06/19/2002 12:00am

    Originally posted by: Daniel

    Any thoughts on how to search through C++ code (reading line by line) and identify a function or a method?? If you do please e-mail me! Thanks!!

    • Bug: formatting strings in file cause buffer overrun

      Posted by shoppinit on 02/05/2008 09:48am

      If the line being scanned contains formatting sequences (eg: sscanf(var, "%d, %s", &m_int, m_str) then fprintf(pTempFile,LineToFile); will search for arguments and not finding any cause a buffer overrun. This line should read: fprintf(pTempFile, "%s", LineToFile); Seems that way to me, at least.

      Reply
    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Learn How A Global Entertainment Company Saw a 448% ROI Every business today uses software to manage systems, deliver products, and empower employees to do their jobs. But software inevitably breaks, and when it does, businesses lose money -- in the form of dissatisfied customers, missed SLAs or lost productivity. PagerDuty, an operations performance platform, solves this problem by helping operations engineers and developers more effectively manage and resolve incidents across a company's global operations. …

  • Live Event Date: December 18, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this upcoming webcast …

Most Popular Programming Stories

More for Developers

RSS Feeds