繁体   English   中英

如何删除包含用户在文件中提供的字符串的整行

[英]how can i delete a whole line containing a string provided by the user in a file

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

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

    #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;
    }

通过将面向字符的输入与fgetc()结合使用需要面向行的输入和输出的操作,您正在给自己制造麻烦。 此外,在您的方法中,您将删除文件中包含单词的每一行,其中you是较少包含的子字符串,例如:

  • “你”、“你的”、“你是”、“你自己”、“你有”等等……

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

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

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

以下示例读取"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()的面向字符的使用进行比较。 如果您还有其他问题,请告诉我。

由于标记为C ++,因此应使用std::stringstd::getline

#include <fstream>
#include <string>

int main()
{
  std::cout << "Enter keyword to search: ";
  std::string keyword;
  std::cin >> keyword;

  std::ifstream text_file("u.txt");
  std::ofstream result_file("u_modified.txt");
  std::string text_from_file;
  while (std::getline(text_file, text_from_file)
  {
      if (text_from_file.find(keyword) == std::string::npos)
      {
         result_file << text_from_file << "\n";
      }
  }
  text_file.close();
  result_file.close();
  return EXIT_SUCCESS;
}

如果是以上代码,将从源文件中读取文本行。 如果存在关键字,则将文本写入结果文件。

编辑1:C样式字符数组
C样式字符数组的一个问题是溢出。 例如,如果char数组的容量为16个字符,并且文件中的文本行为100,则输入将溢出字符数组。 如果缓冲区太大,那是在浪费空间。 如果数组太小,您将无法将整行包含在数组中(或更糟糕的是,关键字可能在读取之间分开)。

使用字符数组,您将不得不重新分配以扩展它。 这意味着分配一个更大的数组(从动态内存),将旧数组复制到新数组,然后删除旧数组。 这种内存管理是使用std::string类型为您执行的。

你没有给chr任何值,它总是A至少在第一个循环中。 是否遗漏了任何代码行? 我建议您检查每一行,直到找到将其保存在字符串中的EOL 然后用它调用strstr() ,如果结果为 NULL,您只需将其复制到另一个文件中。 如果有必要将它保存在同一个文件中,它将更加困难,因为您必须保存指向每一行开头的指针。 如果您正在研究的这一行实际上是必须删除的一行,则您必须从该指针重新复制后面的每一行。 这种方式更难。

祝你好运!

PS:也许这可以帮助,不确定: How do I delete a specific line from text file in C?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM