Questioneer
Questioneer

Reputation: 793

Find and replace function

I am looking to create a C function in which it will search a file based on a user entered entry and be able to replace what was there. I have seen similar c++ examples but I don't know c++ very well. Any suggestions or sample code to help me get started would be amazing. My understanding is I need to open the original file for reading, open a new file for writing, read orig file one line at a time, write that line to the new file, and when done, delete the original file, and rename the new file with the original file's name.

Any suggestions or sample code with an explanation would be most helpful

EDIT Upon further research, I was thinking if I could figure out a way to fread the file, search the file, make the change, and the fwrite it back to the file it would be much much easier.

Upvotes: 0

Views: 446

Answers (3)

wildplasser
wildplasser

Reputation: 44250

A nice workaround to create a lex-scanner with a stupid syntax that only recognises the literals. In the example below "aaaa" is replaced by "AAAA", etcetera. The output is not rescanned.

%%

"aaaa" { fputs("AAAA", stdout ); }

"bbbb" { fputs("BBBB", stdout ); }

"cccc" { fputs("CCCC", stdout ); }

. { ECHO; }

[ \t\r\n]+ { ECHO; }

%%

A makefile fragment for this:

#Makefile

LDFLAGS := -lfl
###################

replace: replace.o
    $(CC) -o $@  $? $(LDFLAGS)

replace.o: replace.c

replace.c: replace.l

(but it would probably be easier to just use sed) A nice property of this method is that (f)lex does all the buffering, and only a minimal amount of buffering is needed. Since lex creates a DFA, the method is also fast: effectively, all the strings are matched in parallel.

Upvotes: 0

RedComet
RedComet

Reputation: 1202

Reading and writing with the line oriented functions is easy, to get user input scanf is often used.

The hard part is doing adequate error checking, which most leave out until is too late.

Here is a nice, but not perfect example using best practices. There are always better and more efficient ways, but to begin with this does the job and gives you and insight of good C.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define BUFFER_SIZE 512

static void searchAndReplace(char* original_file,char* destination_file,char *searchString,char *replacementString){
    FILE* original = NULL;
    FILE* modified = NULL;
    char origLine[BUFFER_SIZE]; //buffer, assuming the longest line will be BUFFER_SIZE -1 characters, being the null terminator the last one
    size_t searchStringLength = strlen(searchString);//length without terminating NULL.
    memset(origLine,0,BUFFER_SIZE);// filling with nulls just in case
    original = fopen(original_file,"r");
    if(!original){
        printf("Error opening file for reading : %s \n",original_file);
        perror("Cause of Error");
        exit(2);
    }
    modified = fopen(destination_file,"w+");
    if(!modified){
        printf("Error opening file for writing: %s \n",destination_file);
        perror("Cause of Error");
        exit(2);
    }

    while(NULL != (fgets(origLine,BUFFER_SIZE,original) )){
        char* searchStringPos=NULL;
        /*it begins to concatenate at the beginning of the string, next position is strlen(searchString) from the last
          searchString pointer position*/
        char* lastConcatPos = origLine;
        if(feof(original) != 0){
            break;
        }
        while ( (searchStringPos = strstr(lastConcatPos,searchString)) != NULL ){
            /* offset between position where searchStringPos was found and the last position being concantenated */
            char tempBuffer[BUFFER_SIZE];
            size_t sizeToConcatenate = (size_t)(searchStringPos - lastConcatPos);
            /* if searchString was located at the beginning of the line or right after the last occurrence do nothing */
            if(sizeToConcatenate >0){
                strncpy(tempBuffer,lastConcatPos,sizeToConcatenate);
                tempBuffer[sizeToConcatenate]='\0';
                fputs(tempBuffer,modified);
            }
            fputs(replacementString, modified);
            lastConcatPos = searchStringPos + searchStringLength;/* continue search after current occurrence*/
        }
        fputs(lastConcatPos,modified);
    }
    fclose(original);
    fclose(modified);
}

static void askUserForInput(char* data_storage,char* text_message){
    int result = 0;
    do{
        //printf("%s, | %s\n  | result = %i",text_message,data_storage,result);
        printf("%s\n",text_message);
        fflush(stdout);
        result = scanf("%s",data_storage);
    }while(result ==0 );
}

int main(int argc,char* argv[]){
    /* Use: program <original_filename> <modified_filename> <string_to_search> <replacement_string> or
     * program for asking the user for input */

    if(argc == 5){
        searchAndReplace(argv[1],argv[2],argv[3],argv[4]);
    }else if(argc == 1){
        char origin_file[128];
        char destination_file[128];
        char search_string[128];
        char replacement_string[128];
        askUserForInput(origin_file,"Enter origin file please");
        askUserForInput(destination_file,"Enter destination file please");
        askUserForInput(search_string,"Enter search string please");
        askUserForInput(replacement_string,"Enter replacement string please");
        searchAndReplace(origin_file,destination_file,search_string,replacement_string);
    }else{
        printf("Usage:\n %s <original_filename> <modified_filename> <string_to_search> <replacement_string>\n or"
               "%s without parameter for asking for input",argv[0],argv[0]);
        exit(1);
    }
    return 0;
}

Edit: There is still much room for improvement, like checking for NULL pointers in each functions, changing searchAndReplace to return a int =0 on success and others according to the type of error and let the caller manage the the rest of the program behavior like trying again instead of exiting the program, etc.

Also printf on the error handling parts should be replaced with fprintf(stderr,"message",..) This are some ideas and concepts which you can use to improve and learn a lot more. Hope you have a lot of fun

Upvotes: 1

Siva Charan
Siva Charan

Reputation: 18064

Try something like this:-

#include <stdio.h>
#include <string.h>

#define MAX_LEN_SINGLE_LINE     120   // ?

int main()
{
    const char fileOrig[32] = "myOriginalFile.txt";
    const char fileRepl[32] = "myReplacedFile.txt";
    const char text2find[80] = "lookforme";
    const char text2repl[80] = "REPLACE_WITH_THIS";

    char buffer[MAX_LEN_SINGLE_LINE+2];
    char *buff_ptr, *find_ptr;
    FILE *fp1, *fp2;
    size_t find_len = strlen(text2find);

    fp1 = fopen(fileOrig,"r");
    fp2 = fopen(fileRepl,"w");

    while(fgets(buffer,MAX_LEN_SINGLE_LINE+2,fp1))
    {
        buff_ptr = buffer;
        while ((find_ptr = strstr(buff_ptr,text2find)))
        {
            while(buff_ptr < find_ptr)
                fputc((int)*buff_ptr++,fp2);

            fputs(text2repl,fp2);

            buff_ptr += find_len;
        }
        fputs(buff_ptr,fp2);
    }

    fclose(fp2);
    fclose(fp1);

    return 0;
}

Upvotes: 1

Related Questions