查找并替换文本文件中的特定字符串,而无需创建新文件

时间:2018-05-24 04:51:09

标签: c string file

以下代码获取原始txt文件,要在文件中搜索的字符串以及用于替换原始文件的新字符串。两根弦的长度是相同的。此代码创建一个新文件(“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 :(得分:2)

简短的回答是你真的不应该,但是如果搜索和替换字符串的长度完全相同,那么它是可行的 - 但是你不能在你写的字符数上犯任何错误 - 否则你会腐败文件。

在您的代码中,如果strlen不相同,则需要return或以其他方式处理错误,而不仅仅是输出该事实。

您已经f打开了"r+",文件位置指示符位于开头,strstr会告诉您是否找到了要替换的单词,然后您需要的只是要做的是将file-positon-indicator设置为strstr返回的指针的位置,并在搜索词上写下替换字符,并重复该行的其余部分。

保持文件位置指示器的偏移量需要注意。阅读完毕后,指示符将超过fgets读取的最后一个字符,因此您需要在代码中按where - write - strlen(write)进行备份。 (注意:偏移量应为负数)

您可以使用fseek来快退并重置文件位置指示符,但使用fgetpos保存当前指标位置并使用fsetpos还原它可能会更好。同时只调用fseek一次,以便替换指标。

将它完全放在一个简短的示例中,并使用buffindreplace代替writewhere,您可以执行类似的操作以下内容:

#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

在shell命令中没有双关语