Извлечение слов из строки (слова разделяются пробелами и табуляцией, возможно, несколькими) - PullRequest
0 голосов
/ 07 марта 2019

Я пытаюсь создать программу на C, которая читает входные данные из файла, пусть это будет Input.inp, который содержит строки со словами, которые разделены пробелами и табуляциями, возможно, несколько, а затем записывают в файл Output.outс каждым словом в строке.Например, входной файл содержит

Hi  my name         is Yang

, тогда выходной файл будет выглядеть следующим образом

Hi
my
name 
is 
Yang

Кроме того, программа прекратит чтение, если достигнет конца файла илидостичь "#".

Ниже мой код.Я получаю символ из файла, затем проверяю, является ли он символом «#» или концом файла или нет.Если это не так, он проверит, является ли символ пробелом, табуляцией или концом строки.Если это не так, то символ будет помещен в строку «слово».Теперь, если мы дойдем до пробела, табуляции или конца строки, я выведу строку «слово», установлю pos обратно в 0 и продолжу это делать.Но это не работает.Может кто-нибудь объяснить, почему мой код не работает, и дать мне указания, как решить эту проблему?

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

#define maxn 300

int main(){
    FILE *fin, *fout;
    fin = fopen("splitwords.inp", "r");
    fout = fopen("splitwords.txt", "w");
    char buffer[maxn], word[maxn], ch, d;
    int i, pos = 0;

    while((ch = fgetc(fin)) != EOF && ch != '#'){
        while(ch != ' ' && ch != '\t' && ch != '\0'){
            word[pos] = ch;
            pos++;
            if((d = fgetc(fin)) == ' ' || d == '\t' || d == '\0'){
                word[pos] = '\0';
                fputs(word, fout);
                printf("%s", word);
                pos = 0;
            }
        }
        if(ch == ' ' || ch == '\t' || ch == '\0') continue;
    }

    fclose(fin);
    fclose(fout);
}

Ответы [ 2 ]

0 голосов
/ 07 марта 2019

Ну, было много ошибок, я добавила свои комментарии:

    while(ch != EOF && ch != '#') {
            word[pos] = ch;
            pos++;
            if(ch == ' ' || ch == '\t' || ch == '\0') {
                word[pos] = '\0';
                fputs(word, fout);
                printf("%s\n", word);
                memset(word, '\0', maxn); //flush word
                pos = 0;

                while (ch == ' ' || ch == '\t' || ch == '\0') { // handle multiple whitespaces
                    ch = fgetc(fin);
                }
            } else {
                ch = fgetc(fin);
            }
    }

Это работает, но:
1. Проверьте pos < maxn, поскольку возможно сбой памяти.
2. Создайте функцию bool isWhitespace(char c);, потому что условие многократного использования с или является некрасивым.
3. Проверьте, что файл открыт правильно fin != NULL && fout != NULL

0 голосов
/ 07 марта 2019

Несколько замечаний по поводу вашего предложения

Как сказано в примечании, когда вы читаете символ, для его сохранения используется int , а не char , вы, вероятно, получили предупреждение от компилятора, чтобы сигнализировать, что проблема на while((ch = fgetc(fin)) != EOF, как , сравнение всегда верно из-за ограниченного диапазона типа данных , это потому, что EOF нельзя сохранить в char . Так что в вашем коде ch и d должно быть int

Проверьте результат fopen , чтобы убедиться, что вы открываете свои файлы.

Лучше добавить (), чтобы избежать возможной проблемы приоритета между операторами, поэтому замените

while((ch = fgetc(fin)) != EOF && ch != '#')

while(ch != ' ' && ch != '\t' && ch != '\0'){

if((d = fgetc(fin)) == ' ' || d == '\t' || d == '\0'){

if(ch == ' ' || ch == '\t' || ch == '\0')

по (без учета других возможных проблем)

while(((ch = fgetc(fin)) != EOF) && (ch != '#'))

while((ch != ' ') && (ch != '\t') && (ch != '\0')){

if(((d = fgetc(fin)) == ' ') || (d == '\t') || (d == '\0')){

if((ch == ' ') || (ch == '\t') || (ch == '\0'))

Как сказано в замечании, если вы введете эти два времени:

while((ch = fgetc(fin)) != EOF && ch != '#'){
   while(ch != ' ' && ch != '\t' && ch != '\0'){

вы никогда не сможете выйти, потому что ch не изменяется внутри, поэтому вы все больше и больше пишете в word и, наконец, из него с неопределенным поведением (обычно сбой ).

Вам не нужно проверять регистр нулевого символа, он отсутствует в текстовом файле.

Вы пропустили управление делом новой строки ('\ n' и '\ r')

Независимо от проблемы, поскольку ch без изменений, вы никогда не проверяете, что прочитанное слово не слишком длинное, чтобы поместиться в слово , вы не можете предположить, что оно будет в любом случае.

В

if((d = fgetc(fin)) == ' ' || d == '\t' || d == '\0'){

вы пропустили управление регистром новой строки, и вам не нужно управлять регистром с нулевым символом.

Линия

if(ch == ' ' || ch == '\t' || ch == '\0') continue;

бесполезен, он находится в конце блока while, поэтому даже без него вы перезагружаетесь


создать программу на C, которая считывает входные данные из файла, пусть это будет Input.inp, который содержит строки со словами, разделенными пробелами и символами табуляции, возможно, несколько, а затем записывает в файл Output.out, где каждое слово включено линия.

Ваша программа также слишком сложна, вам не нужно сохранять слово в памяти (это также имеет преимущество в том, что вы можете управлять словами длиннее 299), ваша цель - поместить каждое слово в разделенные строки в выводе файл, поэтому простое решение:

#include <stdio.h>

int main()
{
  FILE *fin, *fout;

  if ((fin = fopen("splitwords.inp", "r")) == NULL)
    puts("cannot open splitwords.inp");
  else {
    if ((fout = fopen("splitwords.txt", "w"))  == NULL)
      puts("cannot open splitwords.txt");
    else {
      int word = 0; /* not inside a word */
      int c; /* an int to manage EOF */

      while (((c = fgetc(fin)) != EOF) && (c != '#')) {
        if ((c == ' ') || (c == '\t') ||
            (c == '\n') || (c == '\r')) { /* can use isspace() */
          if (word) {
            /* the space finishes a word, add the new line */
            fputc('\n', fout);
            word = 0; /* not in a word now */
          }
        }
        else {
          fputc(c, fout); /* char of word are placed in output file */
          word = 1; /* we are in a word */
        }
      }

      if (word) {
        /* we was reading a word, need to add the final newline */
        fputc('\n', fout);
      }

      fclose(fout);
    }

    fclose(fin);
  }
}

Компиляция и исполнение:

/tmp % gcc -pedantic -Wextra f.c
/tmp % cat splitwords.inp
Hi  my name         is Yang
/tmp % ./a.out
/tmp % cat splitwords.txt 
Hi
my
name
is
Yang

Некоторые объяснения и замечания:

  • после открытия файла я проверяю результат, чтобы убедиться, что fopen success
  • когда я читаю символ, я не сохраняю его в символе , а int , чтобы управлять регистром EOF
  • В приведенном выше коде я сравниваю с пробелом, табуляцией и т. Д., Чтобы вы могли легко увидеть, что я делаю, но есть функция lib, которая делает это прекрасно: isspace , посмотрите на нее и другие полезные функции ( isalpha isdigit ...). Вы можете изменить соответствующую строку, чтобы добавить любые другие символы в качестве разделителя, такие как '-' или пунктуация (',' ';') и т. Д.

Приведенный выше код просто записывает в выходной файл не пробел / tab / newline, и более того, ему просто нужно определить конец слова для добавления новой строки, это цель моей переменной word значение 1, когда ранее управляемый символ не был пробелом / символом табуляции / новой строкой, иначе 0

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...