Мой код не заменяет одно слово другим правильно - PullRequest
0 голосов
/ 21 января 2019

Я только что написал простой код в c, который должен извлечь текст из файла и заменить слово другим.Однако я не знаю почему, но мой код заменяет только слово, начинающееся со второй буквы.Что я делаю неправильно?Это мой код:

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

 int main()
 {



FILE *f;

char sir[20];

if ((f=fopen("fis.txt","r"))==NULL)
{
    printf("Not ok");
    exit(1);
}
gets(sir);
fscanf(f, "%s",sir);

printf("Give the word you are looking for and the word to replace it with");
getchar();

char s1[10],s2[10];
gets(s1);
gets(s2);


char *p, aux[100];
while (p=strstr(sir,s1))

{
    strcpy(aux,p+strlen(s1));
    strcpy(p,s2);
    strcpy(p+strlen(s2),aux);
    puts(sir);


}


}

Ответы [ 2 ]

0 голосов
/ 21 января 2019

Продолжая мой комментарий, никогда не используйте gets(), это ужасно небезопасно и может быть использовано из-за переполнения буфера.Вместо этого, для линейно-ориентированного ввода используйте fgets или POSIX getline.

При чтении текстового файла в качестве ввода, вы корректно смотрите на строчно-ориентированный функции ввода 99% времени.Здесь он будет работать нормально, но вы должны убедиться, что ваш буфер строки достаточен для хранения самой большой строки, которую вы ожидаете.

Вы также не должны пытаться изменить файл, который вы ищете через «на месте».Хотя возможно, что слово для поиска и замены имеет одинаковую длину, вы должны быть осторожны, иначе вы испортите файл.При записи в новый файл вы можете иметь разную длину слов «найти» и «заменить».

Предполагая, что ваше слово будет полностью содержаться в прочитанной вами строке (без переносов или других разделений).несколько строк), вы можете просто прочитать каждую строку, назначить указатель на начальный символ в строке, а затем пройти указатель вниз по строке, сохраняя индекс, когда символ соответствует символам в вашем слове поиска, и выводязамена, когда символы отличаются.Вы должны подумать о том, как вы будете обрабатывать сброс индекса и обрабатывать частичные совпадения, но это просто арифметика.

Например, если у вас есть указатель на поток открытых файлов (например, fp) читая каждую строку в buf и свое слово для поиска в find и строку замены в repl, вы можете сделать что-то похожее на следующее:

    lfind = strlen (find);                  /* length of replacement */

    while (fgets (buf, MAXCH,fp)) {         /* read each line in file */
        p = buf;                            /* pointer to buf */
        while (*p) {
            if (*p == find[ndx])            /* if matches char in find */
                ndx++;                      /* advance index */
            else {  /* otherwise */
                if (ndx) {                  /* if find chars matched */
                    if (ndx == lfind)           /* if full word found */
                        fputs (repl, stdout);   /* output replacement */
                    else {  /* otherwise */
                        int tmp = repl[ndx];    /* save char at ndx */
                        repl[ndx] = 0;          /* nul-terminate repl */
                        fputs (repl, stdout);   /* output replacement */
                        repl[ndx] = tmp;        /* restore char at ndx */
                    }
                    ndx = 0;                /* zero index */
                }
                putchar (*p);       /* output current char */
            }
            p++;
        }
    }
    fclose (fp);                /* close file */

    if (ndx) {                  /* if partial match at end of file */
        repl[ndx] = 0;          /* nul-terminate repl at index */
        fputs (repl, stdout);   /* output final chars */
    }

(вам следует проверитьstrlen каждой строки и то, что она соответствует и не была усечена, в противном случае вы рискуете найти разные части слова, которые вы ищете, в двух разных буферах - это вам осталось)

Примечаниетакже проверка после выхода из цикла есть проверка для вывода любых конечных символов, если ndx не равен нулю.

Помещение в короткий пример, который берет имя файла для чтения и поиска / репликации строк в качестве аргументов 1, 2, 3 для программы (или запросит поиск / реплику, если она не указана в качестве аргумента), вы можете сделать что-то вроде следующего:

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

#define MAXCH 1024
#define MAXWD  128

void handle_args (int argc, char **argv, char *find, char *repl);

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

    size_t lfind, ndx = 0;
    char buf[MAXCH], find[MAXWD] = "", repl[MAXWD] = "", *p;
    FILE *fp = NULL;

    if (argc < 2 ) {    /* validate at least one argument given */
        fprintf (stderr, "error: insufficient input, usage: "
                        "%s filename [find, repl]\n", argv[0]);
        return 1;
    }
    if (!(fp = fopen (argv[1], "r"))) { /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    handle_args (argc, argv, find, repl);   /* set/prompt for find/repl */
    lfind = strlen (find);                  /* length of replacement */

    while (fgets (buf, MAXCH,fp)) {         /* read each line in file */
        p = buf;                            /* pointer to buf */
        while (*p) {
            if (*p == find[ndx])            /* if matches char in find */
                ndx++;                      /* advance index */
            else {  /* otherwise */
                if (ndx) {                  /* if find chars matched */
                    if (ndx == lfind)           /* if full word found */
                        fputs (repl, stdout);   /* output replacement */
                    else {  /* otherwise */
                        int tmp = repl[ndx];    /* save char at ndx */
                        repl[ndx] = 0;          /* nul-terminate repl */
                        fputs (repl, stdout);   /* output replacement */
                        repl[ndx] = tmp;        /* restore char at ndx */
                    }
                    ndx = 0;                /* zero index */
                }
                putchar (*p);       /* output current char */
            }
            p++;
        }
    }
    fclose (fp);                /* close file */

    if (ndx) {                  /* if partial match at end of file */
        repl[ndx] = 0;          /* nul-terminate repl at index */
        fputs (repl, stdout);   /* output final chars */
    }

    return 0;
}

/* simple function to set find/repl from command line, or 
 * prompt for input if no arguments given.
 */
void handle_args (int argc, char **argv, char *find, char *repl)
{
    if (argc < 3) {
        fputs ("enter find word: ", stdout);
        if (scanf ("%127s", find) != 1) {
            fputs ("error: invalid input.\n", stderr);
            exit (EXIT_FAILURE);
        }
    }
    else {
        size_t len = strlen (argv[2]);
        if (len < MAXWD)
            memcpy (find, argv[2], len + 1);
        else {
            fputs ("error: find argument too long.\n", stderr);
            exit (EXIT_FAILURE);
        }
    }

    if (argc < 4) {
        fputs ("enter repl word: ", stdout);
        if (scanf ("%127s", repl) != 1) {
            fputs ("error: invalid input.\n", stderr);
            exit (EXIT_FAILURE);
        }
    }
    else {
        size_t len = strlen (argv[3]);
        if (len < MAXWD)
            memcpy (repl, argv[3], len + 1);
        else {
            fputs ("error: repl argument too long.\n", stderr);
            exit (EXIT_FAILURE);
        }
    }
}

Пример входного файла

$ cat ../dat/qbfox3.txt
A quick brown fox jumps over the lazy dog.
A slow green dog jumps on top of the blue cat.
A quick blue bird flew over the lazy dog too.

Пример Использование / Вывод

$ ./bin/file_replace_fgets_stdout ../dat/qbfox3.txt dog duck
A quick brown fox jumps over the lazy duck.
A slow green duck jumps on top of the blue cat.
A quick blue bird flew over the lazy duck too.

Или проверка угловых случаев замены первого и последнего символа, например,

$ ./bin/file_replace_fgets_stdout ../dat/qbfox3.txt "." "*"
A quick brown fox jumps over the lazy dog*
A slow green dog jumps on top of the blue cat*
A quick blue bird flew over the lazy dog too*

$ ./bin/file_replace_fgets_stdout ../dat/qbfox3.txt A B
B quick brown fox jumps over the lazy dog.
B slow green dog jumps on top of the blue cat.
B quick blue bird flew over the lazy dog too.

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

0 голосов
/ 21 января 2019

Я считаю, что ваш подход слишком сложен, его можно сделать намного проще, просто переместив указатели.Вот примерный (1) набросок:

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

int main(void)
{
  /* Input file */
  FILE *f;
  /* Buffer for content of input-file */
  char sir[100] = { 0 };
  /* Temporary memory to hold the result */
  /* char tmp[100] = {0}; */
  /* Memory for the word to find and the one to replace */
  char s1[10], s2[10];
  /* Pointer to the occurrence of the word to replace */
  char *p;
  /* Pointer to sir, the memory holding the content of the file */
  char *c;

  if ((f = fopen("fis.txt", "r")) == NULL) {
    printf("Not ok");
    exit(EXIT_FAILURE);
  }
  /* Read content of file, leave room for the final `\0` */
  /* TODO: check return of fread() */
  fread(sir, 99, 1, f);

  printf("Give the word you are looking for and the word to replace it with: \n");
  /* TODO: check return of scanf() */
  /* HINT: you should read the two words separately. Ask for the word to find first,
   * read it and repeat that for the word to replace. */
  scanf("%9s %9s", s1, s2);
  /* Give user a change to stay in control. */
  printf("You are looking for %s and want it to be replaced with %s\n", s1, s2);

  /* We want to move through the input, we can do it quite comfortably with a pointer */
  c = sir;
  /* For every occurrence of the word to replace */
  while ((p = strstr(c, s1)) != NULL) {
    /* Print all characters up to the pointer p */
    /* TODO: change it to fill tmp instead. */
    /* HINT: I would use a pointer to tmp to do it but check the length! */
    while (c < p) {
      printf("%c", *c);
      c++;
    }
    /* Print the replacement / fill tmp */
    printf("%s", s2);
    /* Move the pointer to sir to the point in sir after the original word */
    c = p + strlen(s1);
  }
  /* Print / fill tmp with the rest of sir. Check the length if you use tmp! */
  printf("%s", c);
  /* Get outta here! */
  exit(EXIT_SUCCESS);
}
...