Как записать строку в файл в разные строки в C - PullRequest
0 голосов
/ 27 декабря 2018

У меня есть программа, которая заменяет слово в файле другим, но в новом файле все строки пишутся одной строкой, а не в разных строках и абзацах, как требуется.

Я попытался добавить '\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 голосов
/ 27 декабря 2018

То есть вы хотите изменить слова в файле, но оставить все пробелы как есть?Тогда важно читать и писать пробелы.Использование функций чтения, пропускающих пробелы, вам мало чем поможет.

Вот общая версия цикла чтения-изменения.Исправление ошибок и распространение их на конкурирующую программу, включая обработку ошибок, оставлено читателю в качестве упражнения

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"); 
0 голосов
/ 27 декабря 2018

Простая причина в том, что вы не выводите новую строку в файл.fscanf не включает перевод строки в s (потому что вы специально опускаете его с [^\n], что означает «символы , отличные от перевод строки»).

Если вы простодобавьте putc('\n', f2); в самом конце внешнего цикла while, все работает нормально.

В качестве альтернативы, вы можете просто прочитать с помощью fgets, что включает в себя символ новой строки в строке.Дополнительным преимуществом является то, что fgets заставляет вас указывать максимальную длину в качестве аргумента, в то время как защита от чрезмерной длины строки с помощью fscanf требует, чтобы вы указали длину в самой строке формата.

(Обратите внимание, что printf("%s", s); не влияет на то, что входит в файл, так как выводит stdout.)

0 голосов
/ 27 декабря 2018

Вы должны использовать fgets() для чтения из входного файла вместо fscanf(f1,"%[^\n]%*c", &s) по нескольким причинам:

  • вы не даете fscanf() максимальному количеству символов для хранения в s: любая достаточно длинная строка во входном файле вызовет неопределенное поведение.
  • вы читаете строку из f1 и явно пропускаете новую строку, это объясняет, почему новая строка никогда не записывается в f2.
  • fscanf() завершится с ошибкой в ​​пустой строке, поскольку нет символов, отличных от \n для чтения в s, s не изменяется и обрабатывается так же, как и в предыдущей строке (или неопределенное поведение в первой строке)), и цикл повторяется в том же месте во входном файле, фактически застрял навсегда, записывая в 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;
}
0 голосов
/ 27 декабря 2018

первой ошибкой является присвоение fscanf адреса s , fscanf(f1,"%[^\n]%*c",&s) должно быть fscanf(f1,"%[^\n]%*c",s)

в любом случае, просто замените fscanf напросто fgets и все будет в порядке, вы не потеряете \ n

PS, если вы не можете быть уверены, что MAX недостаточно для обработки линий, вы должны управлять случаем, когда линия обрезаетсянесколько при прочтении, и из-за этого может быть слово для замены в разрезе.Есть несколько способов сделать это.

...