Найти и заменить конкретную строку в текстовом файле, не создавая новый файл - PullRequest
0 голосов
/ 24 мая 2018

Следующий код получает оригинальный текстовый файл, строку для поиска в файле и новую строку для замены исходного.Длина двух строк будет одинаковой.Этот код создает новый файл («new.txt»), записывает туда замененный текст, а затем удаляет исходный файл и переименовывает новый в исходный.

Вопрос в том, как я могу сделать этокод, чтобы функционировать то же самое, но не создавать новый файл?Другими словами, я хочу просто изменить сам оригинальный файл.Я попытался fprintf к исходному файлу (f), но его вывод был странным.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 1024

int main(int argc, char *argv[])
{
    FILE *f = fopen(argv[1], "r+");
    FILE *f2 = fopen("new.txt", "a+");

    if(strlen(argv[2])!=strlen(argv[3]))
        printf("[%s] and [%s] have different lengths\n", argv[2], argv[3]);

    char write[MAX];
    int where;
    char* string = NULL;

    int len = strlen(argv[2]);
    int i=0;

    while(fgets(write, MAX, f)!=NULL)
    {
        if(NULL!=(string = strstr(write, argv[2])))
        {
            where = (int)(string - write);
            strncpy(write+where, argv[3], len);
        }
        fprintf(f2, "%s", write);
    }
    remove(argv[1]);
    rename("new.txt", argv[1]);
    return 0;
}

1 Ответ

0 голосов
/ 24 мая 2018

Короткий ответ: вы действительно не должны этого делать, но это выполнимо, если строки поиска и замены имеют одинаковую длину - но вы не можете ошибиться в количестве написанных вами символов - или вы испортите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

( без каламбура в предназначенной команде оболочки )

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...