如何在C中的不同行中将字符串写入文件

时间:2018-12-27 12:04:36

标签: c string file replace word

我有一个程序,可以用一个文件替换一个文件中的一个单词,但是在新文件中,所有行都写成一行,而不是按要求写在不同的行和段落中。

我尝试在从原始文件读取的每一行的末尾添加'\n',但是它不起作用。

这是我的代码:

int main() {
    FILE *f1, *f2;
    char word[MAX], fname[MAX];
    char s[MAX], replace[MAX];
    char temp[] = "temp.txt", *p1, *p2;
    printf("Enter your input file name:");
    fgets(fname, MAX, stdin);
    fname[strlen(fname) - 1] = '\0';

    scanf("%s", word);

    scanf("%s", replace);

    f1 = fopen(fname, "r");
    if (!f1) {
        printf("Unable to open the input file!!\n");
        return 0;
    }
    f2 = fopen(temp, "w");
    if (!f2) {
        printf("Unable to open temporary file!!\n");
        return 0;
    }

    while (fscanf(f1,"%[^\n]%*c", &s) != EOF) {
        printf("%s",s); //I wanted to see what happens when I'm reading from the file. Previously I added at the end of string s the char '\n' but it didnt work

        if (strstr(s, word)) {
            p2 = s;
            while (p1 = strstr(p2, word)) {
                while (p2 != p1) {
                    fputc(*p2, f2);
                    p2++;
                }
                p1 = p1 + strlen(word);
                fprintf(f2, "%s", replace);
                p2 = p1;
            }
            while (*p2 != '\0') {
                fputc(*p2, f2);
                p2++;
            }
        } else {
            fputs(s, f2);
        }
    }

    fclose(f1);
    fclose(f2);

    remove(fname);

    rename(temp, fname);
    return 0;
}

4 个答案:

答案 0 :(得分:1)

The simple reason is that you are not outputting a newline to the file. The fscanf doesn't include the newline in s (because you specifically omit it with [^\n], which means "characters other than newline").

If you just add putc('\n', f2); at the very end of the outer while loop, it works fine.

Alternatively, you could just read with fgets, which does include the newline in the string. An added benefit is that fgets forces you to specify the maximum length as an argument, while guarding against excessive line length with fscanf requires you to put the length in the format string itself.

(Note that the printf("%s", s); has no effect on what goes into the file, since it outputs to stdout.)

答案 1 :(得分:1)

出于多种原因,您应该使用fgets()而不是fscanf(f1,"%[^\n]%*c", &s)来读取输入文件:

  • 您没有将fscanf()的最大字符数存储到s中:输入文件中任何足够长的行都会导致未定义的行为。
  • 您从f1中读取了该行,并明确跳过了换行符,这说明了为什么从未将换行符写入f2
  • fscanf()将在空行上失败,因为没有与\n相同的字符可以读入ss未被修改并且像上一行一样得到处理(或第一行中未定义的行为),并且循环在输入文件中的同一位置进行迭代,有效地永久地阻塞了对f2的写操作,无济于事...

以下是经过纠正和简化的版本:

#include <stdio.h>
#include <string.h>

#define MAX  100

int main() {
    FILE *f1, *f2;
    char word[MAX], fname[MAX];
    char s[MAX], replace[MAX];
    char temp[] = "temp.txt";
    char *p1, *p2;

    printf("Enter your input file name: ");
    if (!fgets(fname, sizeof fname, stdin))
        return 1;
    fname[strcspn(fname, "\n")] = '\0';  /* strip the newline if present */

    printf("Enter the word to search: ");
    if (scanf("%99s", word) != 1)
        return 1;

    printf("Enter the replacement word: ");
    if (scanf("%99s", replace) != 1)
        return 1;

    f1 = fopen(fname, "r");
    if (!f1) {
        fprintf(stderr, "Unable to open the input file %s\n", fname);
        return 1;
    }
    f2 = fopen(temp, "w");
    if (!f2) {
        fprintf(stderr, "Unable to open temporary file %s\n", temp);
        return 1;
    }

    while (fgets(s, sizeof s, f1)) {
        p1 = s;
        while ((p2 = strstr(p1, word)) != NULL) {
            while (p1 < p2) {
                fputc(*p1++, f2);
            }
            fputs(replace, f2);
            p1 += strlen(word);
        }
        fputs(p1, f2);
    }

    fclose(f1);
    fclose(f2);

    remove(fname);
    rename(temp, fname);
    return 0;
}

但是请注意,如果输入文件中的行很长且匹配项跨越fgets()读取的多个块,则程序将丢失这些匹配项。

这里是避免此问题的另一种方法:

#include <stdio.h>
#include <string.h>

#define MAX  100

int main() {
    FILE *f1, *f2;
    char fname[MAX], word[MAX], replace[MAX];
    char temp[] = "temp.txt";
    char *p1 *p2;
    int c;

    printf("Enter your input file name: ");
    if (!fgets(fname, sizeof fname, stdin))
        return 1;
    fname[strcspn(fname, "\n")] = '\0';  /* strip the newline if present */

    printf("Enter the word to search: ");
    if (scanf("%99s", word) != 1)
        return 1;

    printf("Enter the replacement word: ");
    if (scanf("%99s", replace) != 1)
        return 1;

    f1 = fopen(fname, "r");
    if (!f1) {
        fprintf(stderr, "Unable to open the input file %s\n", fname);
        return 1;
    }
    f2 = fopen(temp, "w");
    if (!f2) {
        fprintf(stderr, "Unable to open temporary file %s\n", temp);
        return 1;
    }

    p2 = word;
    while ((c = getc(f1)) != EOF) {
        if (c != '\0' && *p2 == (char)c) {
            p2++;
            if (*p2 == '\0') {
                fputs(replace, f2);
                p2 = word;
            }
        } else {
            for (p1 = word; p1 < p2;) {
                putc(*p1++, f2);
                /* find potential match for special cases: find aab in aaab */
                if (!memcmp(word, p1, p2 - p1) && word[p2 - p1] == (char)c)
                    p2 = word + (p2 - p1) + 1;
                    p1 = word;
                    break;
                }
            }
            if (p1 == p2) {
                putc(c, f2);
            }
        }
    }
    /* flush potential partial match at end of file */
    for (p1 = word; p1 < p2; p1++) {
        putc(*p1, f2);
    }
    fclose(f1);
    fclose(f2);

    remove(fname);
    rename(temp, fname);
    return 0;
}

答案 2 :(得分:0)

第一个错误是将 s 的地址提供给fscanf,@resultant_visit_hash = arr.inject { |acc, next_obj| acc.merge(next_obj) { |key,arg1,arg2| arg1+agr2 if (arg1.class == Fixnum && arg2.class == Fixnum) } } 必须为fscanf(f1,"%[^\n]%*c",&s)

无论如何,只需将您的 fscanf 替换为简单的 fgets ,一切都会好的,您不会松动\ n

P.S。如果不能确定MAX不足以处理行,则必须管理在读取时将某行切成几行的情况,因此可能是要在cut中替换的单词。有几种方法可以做到这一点。

答案 3 :(得分:0)

因此,您想修改文件中的单词,但保持所有空白不变?然后,读取和写入空白很重要。使用跳过空白的读取功能不会有多大帮助。

这是读取-修改循环的通用版本。修正错误并将其扩展到包括错误处理在内的竞争程序中,留给读者练习

while (1)
  {
    // Read the next character
    int ch = fgetc(infile);
    if (ch == EOF)
       break;  // read error or eof

    if (isspace(ch))
       {
          // The character was a whitespace, so we copy it to the outputstream
          int err = fputc(ch, outfile);
          if (err == EOF)
            break; // error
       }
    else
      {
        // The next character was not a whitespace, so we put it back in the
        //  inputstream for scanf to find it
        ungetc(ch, instream);

        char word[64]; // Just assume for simplicity that no words are longer 
                       // than 63 character.

        // Read the next string, making sure we don't read more than the buffer
        // can handle. A robust program should do something useful if words are
        // actually longer than 63 characters
        int len = fscanf(infile, "%63s", word);

        if (len == EOF)
           break;  // error (should not happen since there is guarantied to be
                     // one non-whitespace character in the stream)

        char mod_word[64];
        modify_word(mod_word, word);

        int err = fputs(mod_word, outfile);
        if (err == EOF)
           break; // error
     }
}

// Check for read-write errors
if (ferror(infile))
  perror("Failure reading from input file");
if (ferror(outfile))
  perror("Failure writing to output file");