Короткий ответ: вы действительно не должны этого делать, но это выполнимо, если строки поиска и замены имеют одинаковую длину - но вы не можете ошибиться в количестве написанных вами символов - или вы испортитеfile.
В вашем коде, если strlen
не то же самое, вам нужно return
или иным образом обработать ошибку, а не просто вывести этот факт.
У вас уже есть f
, открытый как "r+"
с указателем положения файла в начале, strstr
сообщит вам, если вы нашли слово для замены, тогда все, что вам нужно сделать, этоустановите указатель file-positon в положение указателя, возвращаемого strstr
, и запишите заменяющие символы в поисковом термине и повторите для оставшейся части строки.
Сохранение смещения для позиции файлаИндикатор прямо будет нуждаться в тщательном внимании.После прочтения индикатор будет на единицу после последнего символа, прочитанного fgets
, поэтому вам необходимо выполнить резервное копирование на where - write - strlen(write)
в своем коде.( примечание: смещение должно быть отрицательным)
Вы можете использовать fseek
для перемотки и сброса индикатора положения файла, но вам, вероятно, лучше подать, используя fgetpos
чтобы сохранить текущее положение индикатора и fsetpos
, чтобы восстановить его, при этом вызывая fseek
только один раз, чтобы установить положение индикатора для замены.
В целом коротко рассмотрим его и используя buf
, find
и replace
, вместо write
и where
, вы можете сделать что-то вроде следующего:
#include <stdio.h>
#include <string.h>
#define MAXC 1024
int main (int argc, char **argv) {
char buf[MAXC], *find, *replace; /* read buf, find, replace pointers */
size_t findlen; /* length of find string */
FILE *f = NULL; /* file pointer */
if (argc < 4 ) { /* validate sufficient arguments given */
fprintf (stderr, "error: insufficient input, "
"usage: %s file find repl\n", argv[0]);
return 1;
}
find = argv[2]; /* set find, replace & length */
replace = argv[3];
findlen = strlen (find);
if (findlen != strlen (argv[3])) { /* validate length the same */
fprintf (stderr, "error find/replace lengths differ.\n");
return 1;
}
if (!(f = fopen (argv[1], "r+"))) { /* validate file open for reading+ */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
while (fgets (buf, MAXC, f)) { /* read each line into buf */
char *findp = buf; /* find pointer to search buf */
/*
* buf length and search term split at end validation omitted.
*/
while ((findp = strstr (findp, find))) { /* while find found */
fpos_t pos; /* object to hold current file position */
/* compute characters to backup (negative) */
long backup = (long)(findp - buf) - strlen(buf);
fgetpos (f, &pos); /* save the current position */
fseek (f, backup, SEEK_CUR); /* backup */
for (char *p = replace; *p; p++)
fputc (*p, f); /* overwrite char-by-char */
fsetpos (f, &pos); /* reset file position */
findp += findlen; /* advance beyond current find */
}
}
if (fclose (f) == EOF) /* validate close after write */
perror ("fclose(f)");
return 0;
}
Пример входного файла
$ cat dat/dogfleas.txt
my dog has fleas
other dogs run away
my dog is an ichy dog
Пример использования и результирующий файл
$ ./bin/file_replace_in_place dat/dogfleas.txt dog cat
$ cat dat/dogfleas.txt
my cat has fleas
other cats run away
my cat is an ichy cat
( без каламбура в предназначенной команде оболочки )