问题
I have program that replaces a word in a file with another one, but in the new file the lines are all written as one line, not in different lines and paragraphs as required.
I tried adding '\n'
at the end of each line I am reading from the original file, but it is not working.
This is my code:
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;
}
回答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
.)
回答2:
You should use fgets()
to read from the input file instead of fscanf(f1,"%[^\n]%*c", &s)
for multiple reasons:
- you do not give
fscanf()
to maximum number of characters to store intos
: any sufficiently long line in the input file will cause undefined behavior. - you read the line from
f1
and explicitly skip the newline, this explains why the newline never gets written tof2
. fscanf()
will fail on an empty line because there are no characters different from\n
to read intos
,s
is unmodified and gets handled like the previous line (or undefined behavior on the first line), and the loop iterates at the same spot in the input file, effectively stuck forever writing tof2
to no avail...
Here is a corrected and simplified version:
#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;
}
Note however that if the input file has very long lines with matches spanning multiple chunks read by fgets()
, these matches will be missed by the program.
Here is a different approach to avoid this problem:
#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;
}
回答3:
a first error is to give the address of s to fscanf, fscanf(f1,"%[^\n]%*c",&s)
must be fscanf(f1,"%[^\n]%*c",s)
anyway, just replace your fscanf by a simple fgets and all will be ok, you will not loose \n
P.S. if you cannot be sure MAX is not enough to handle lines you have to manage the case a line is cut in several at read, and may be the word to replace in cut because of that. There are several ways to do that.
回答4:
So you want modify words in a file, but keep all whitespace as is? Then it is important to read and write the whitespace. Using read-functions that skips whitespace won't help you much.
Here is a generic version of a read-modify loop. Fixing bugs and extending it to a compete program, including error handling, is left as exercise to the reader
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");
来源:https://stackoverflow.com/questions/53944779/how-to-write-string-to-file-in-different-lines-in-c