首页 > 解决方案 > 如何删除包含用户在文件中提供的字符串的整行

问题描述

我需要删除包含用户插入的字符串的整行,我很难弄清楚如何删除这一行,这就是我到目前为止所绑定的。

例如,如果u.txt包含:
1 hello world
2 你在哪里
* 用户输入:你*
u.txt现在包含
1.hello world

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

    int main()
    {
    FILE *tr1, *tr2;
    char *p;
    char chr;
    char scanner [10];
    int t = 1;
    int sc;
    tr1 = fopen("u.txt", "r");
    chr = getc(tr1);
    while (chr != EOF)
    {
        printf("%c", chr);
        chr = getc(tr1);
    }  
      printf("input your word to search:");
      scanf("%s",scanner);
      rewind(tr1);
      tr2 = fopen("replica.txt", "w");
      chr = 'A';

      while (chr != EOF)
      {
       //expect the line to be deleted
        sc= strstr(chr,scanner);
        if (!sc)
        {
           //copy all lines in file replica.txt
           putc(chr, tr2);
        }

      fclose(tr1);
      fclose(tr2);
      remove("u.txt");
      rename("replica.txt", "u.txt");
      tr1 = fopen("u.txt", "r");
      chr = getc(tr1);
       while (chr != EOF)
      {
               printf("%c", chr);
               chr = getc(tr1);
     }
     fclose(tr1);
     return 0;
    }

标签: c

解决方案


通过使用面向字符的输入和需要面向行的输入和输出fgetc()的操作,您正在使自己变得困难。此外,在您的方法中,您将删除文件中包含包含较少子字符串的单词的每一行,例如:you

  • “你”、“你的”、“你是”、“你自己”、“你已经”等等……

对于确保不删除包含单词的行的简单方法"you",您可以简单地检查以确保单词前后的字符是空格。您可以使用提供的宏来简化检查。isspace()ctype.h

当您遇到面向行的问题时,请使用面向行的输入和输出函数,例如fgets()POSIXgetline()用于输入和puts()/或fputs()输出。唯一需要注意的是,面向行的输入函数读取并'\n'在它们填充的缓冲区中包含尾随。只需在必要时'\n'使用nul 终止字符'\0'(或简单地0)覆盖尾随即可删除。

使用面向行的方法将大大简化您的任务,并提供一种方便的方式,将您保留的行写入到输出文件中,而不是逐个字符地循环。使用面向字符的方法并没有错,而且它本身并不比面向行的方法慢——它只是不太方便。使工具与工作相匹配。

以下示例在删除不需要的行的情况下进行读取"u.txt"和写入,同时保留单词是所查找单词的包含较少的子字符串的行。"v.txt"rename()remove()留给您,因为您现有代码的那部分没有任何问题)

简单地使用足够大小的固定缓冲区是进行面向行输入的最简单方法。您通常会知道最大的预期线是什么,只需使用足以处理它的缓冲区(不要吝啬!)。大多数行的长度不超过 80-120 个字符。一个 1024 个字符的固定数组绰绰有余。只需声明一个数组用作缓冲区来保存读取的每一行,例如:

#define MAXW   32       /* max chars in word to find */
#define MAXC 1024       /* max chars for input buffer */

int main (int argc, char **argv) {

    char buf[MAXC],         /* buffer to hold each line */
        word[MAXW];         /* user input to find/delete line */
    size_t wordlen = 0;     /* length of user input */
    FILE *ifp, *ofp;        /* infile & outfile pointers */

您可以验证是否在命令行上为输入和输出文件名提供了足够的参数,然后打开并验证您的每个文件,例如

    if (argc < 3) { /* validate at least 2 program arguments given */
        printf ("usage: %s infile outfile\n", strrchr (argv[0], '/') + 1);
        return 1;
    }

    if (!(ifp = fopen (argv[1], "r"))) {    /* open/validate open for reading */
        perror ("fopen-ifp");
        return 1;
    }

    if (!(ofp = fopen (argv[2], "w"))) {    /* open/validate open for writing */
        perror ("fopen-ofp");
        return 1;
    }

现在只需从用户那里获取输入并删除尾随'\n'. 使用strcspn您可以获得用户输入的长度,同时'\n'在单个调用中覆盖尾随。请参阅:man 3 strspn,例如

    fputs ("enter word to find: ", stdout); /* prompt for input */
    fflush (stdout);                        /* optional (but recommended) */

    if (!fgets (word, MAXW, stdin)) {       /* read/validate word to find */
        fputs ("(user canceled input)\n", stdout);
        return 1;
    }

    /* get wordlen, trim trailing \n from find */ 
    word[(wordlen = strcspn (word, "\n"))] = 0;

现在只需一次读取一行并在该行内搜索word并验证它是一个完整的单词而不是一个更大单词的一部分。将所有不包含word单独的行写入输出文件:

    while (fgets (buf, MAXC, ifp)) {    /* read each line */
        char *p = strstr (buf, word);   /* search for word */
        if (!p ||                                       /* word not in line */
            (p != buf && !isspace (*(p - 1))) ||        /* text before */
            (!isspace (p[wordlen]) && p[wordlen] != 0)) /* text after */
            fputs (buf, ofp);           /* write line to output file */
    }

注意:标题中提供了isspace()检查字符是否为空格的宏ctype.h

关闭这两个文件,除了你的remove()rename()你就完成了。但是,请注意,您应该始终在写入fclose()后进行验证,以确保您捕获与关闭时刷新文件流相关的任何错误,否则这些错误不会通过单独验证每个写入来捕获,例如

    if (fclose (ofp) == EOF) {      /* validate EVERY close-after-write */
        perror ("fclose-ofp");
        remove (argv[2]);
    }

    fclose (ifp);   /* close input file */
}

添加所需的头文件,您就有了一个工作示例。您可以将示例按如下方式使用:

示例输入文件

$ cat dat/u.txt
hello world
how are you
show yourself
you're missing

示例使用

$ ./bin/filermline dat/u.txt dat/v.txt
enter word to find: you

生成的输出文件

$ cat dat/v.txt
hello world
show yourself
you're missing

仔细查看并比较面向行的方法与您使用面向字符的fgetc(). 如果您还有其他问题,请告诉我。


推荐阅读