How would one replace every instance of a given string in a text file in a simple C program ?
One would think this is a question easily Googled, yes ?
At the time of asking,SanFoundry, TutorialsPoint, GeeksforGeeks, w3resource, Codeforwin, a blog, GeeksforGeeks (twice) and even Code Review SE have badly broken posts that will likely give dysfunctional code to desperate people on deadlines. These are unacceptably bad answers, except maybe the C.R. SE, which addresses its limitations clearly.
This had to thus be addressed in Q&A format on a reliable platform, like Stack Overflow.
My initial answer replaces 'phrases' or 'strings' in the most technical and strict meaning of the words. However, as disclaimed, it will also replace the target where it is a part of another string/word/phrase - for instance, 'the' in 'them'.
If you want to replace "Bob" in "Bob's", that is the one to go for. However, unless used with care, it can be too powerful and destructive.
This answer replaces 'words' (word = string of ASCII characters of decimal value 32 to 126, terminated by any white space character). I.e,Only the word 'is' is changed, not the 'is' inside 'This'.
Algorithm/Steps :
0. , 1. & 2. same as in first answer.
3. Infinite Loop :
i) Get a character from file.
ii) If character == EOF, break the loop.
iii) Else if character is white space character, directly write it to tmp file.
iv) Else take the word, and put it to a buffer. Using strcmp()
, compare buffer and target.
v) If word is the same, use strcpy()
to move replacement to buffer.
vi) Write buffer to file.
4. and 5. same as 9. and 10. of original answer.
Code :
#include <stdio.h>
#include <string.h>
#define MAX_W 501
#define MAX_F 261
void eat(void); //clears stdin
int main(){
printf("\nKeep a backup of your file in case of undesirable effects.\n");
char frep[MAX_F]; printf("\n Filename : "); scanf("%260[^\n]",frep);eat(); // stores fname in frep[], clears stdin
FILE * rep = fopen(frep,"r");FILE * tmp = fopen("Temp.Ctt","w");// opens file for reading and tmp for writing
if(rep==NULL||tmp==NULL){
// if files could not be opened
perror("\nError ");
}
else{
char target[MAX_W]; printf("\n Target : "); scanf("%500s",target);eat(); // gets target word
char replace[MAX_W]; printf("\n Replacement : "); scanf("%500[^\n]",replace);eat();// gets its replacement
while(1){
int ch = fgetc(rep);
if(ch==EOF)
break;
else if(ch==' '||ch=='\t'||ch=='\n'||ch == '\r')
fputc(ch,tmp);// directly write whitespace chars
else{
char buffer[MAX_W];
fseek(rep,-1,SEEK_CUR);
// move FILE pointer 1 byte back to read entire word, not from 2nd char onwards
fscanf(rep,"%500s",buffer);
if(strcmp(buffer,target)==0)
strcpy(buffer,replace);
fprintf(tmp,"%s",buffer);
}
}
fclose(rep); int chk =fclose(tmp);
if(chk==EOF){
remove("Temp.Ctt"); perror("\nFailed ");
}
else{
if(rename("Temp.Ctt",frep)==0)
printf("\nSucess.\n\nReplaced any instances of \"%s\" with \"%s\".\n",target,replace);
else{
remove(frep);
if(rename("Temp.Ctt",frep)==0)
printf("\nSucess.\n\nReplaced any instances of \"%s\" with \"%s\".\n",target,replace);
else{
remove("Temp.Ctt"); perror("\nFailed ");
}
}
}
}
return 0;
}
void eat()
{
int eat;while ((eat = getchar()) != '\n' && eat != EOF);
}