Программа на C, проблема с переводами строк и вкладками рядом друг с другом - PullRequest
3 голосов
/ 20 октября 2010

Вот мой оригинальный код:

#include <stdio.h>

#define IN  1   // inside a word
#define OUT 0   // outside a word

// program to print input one word per line

int main(void)
{
  int c, state;

  state = OUT;
  while ((c = getchar()) != EOF) {
    if (c == ' ' || c == '\n' || c == '\t') {
      state = OUT;
      printf("\n");
    }
    else if (state == OUT) {
      state = IN;
    }
    if (state == IN) {
      putchar(c);
    }
  }
  return 0;
}

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

#include <stdio.h>

#define IN  1   // inside a word
#define OUT 0   // outside a word

// program to print input one word per line, corrected bug if there was
// more than one space between words to only print one \n

int main(void)
{
  int c, last, state;

  last = EOF;
  state = OUT;
  while ((c = getchar()) != EOF) {
    if (c == ' ' || c == '\n' || c == '\t') {
      if (last != c) {
        state = OUT;
        printf("\n");
      }
    }
    else if (state == OUT) {
      state = IN;
    }
    if (state == IN) {
      putchar(c);
    }
    last = c;
  }
  return 0;
}

Это решило эту проблему, за исключением того, что теперь, если рядом с ними есть [пустая] [вкладка], для обеих строк выводится новая строка.

Может ли кто-нибудь помочь, пожалуйста?

Ответы [ 4 ]

6 голосов
/ 20 октября 2010

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

Изменить:

if (c == ' ' || c == '\n' || c == '\t') {
    state = OUT;
    printf("\n");
}

на:

if (c == ' ' || c == '\n' || c == '\t') {
    if (state == IN) printf("\n");
    state = OUT;
}

На самом деле, чтоПервоначально я думал, что предложил бы перечисление состояний в соответствии с:

enum eState {IN, OUT};
:
enum eState state = OUT;

, но для простого конечного автомата только с двумя состояниями вы можете просто использовать логическое значение:

#include <stdio.h>

#define FALSE (1==0)
#define TRUE  (1==1)
// Or: enum eBoolean {FALSE = 0, TRUE = 1};

int main (void) {
    int ch;
    int inWord = FALSE;     // Or: enum eBoolean inWord = FALSE;

    // Process every character.
    while ((ch = getchar()) != EOF) {
        // Check for whitespace.
        if (ch == ' ' || ch == '\n' || ch == '\t') {
            // Check if transitioning nonwhite to white.
            if (inWord) {
                printf("\n");
            }

            // Mark white no matter what.
            inWord = FALSE;
        } else {
            // Mark non whitespace.
            inWord = TRUE;
        }

        // If not whitespace, output character.
        if (inWord) {
            putchar(ch);
        }
    }
    return 0;
}
2 голосов
/ 20 октября 2010

Как сказал paxdiablo, ваша программа является типичным автоматом с конечным состоянием (FSA). Вы должны напечатать новую строку при переходах из состояния OUT в состояние IN и только затем.

Ниже я бы написал такой код. В этом конкретном случае это можно сделать проще, но структура интересна, потому что типична и применима к любому FSA. У вас есть большой внешний переключатель с чехлом для каждого состояния. Внутри каждого случая вы получаете другой, который материализует переходы, здесь событие перехода - это вводимые символы. Осталось только подумать о том, что следует делать для каждого перехода. Также эта структура довольно эффективна.

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

#include <stdio.h>

#define IN  1   // inside a word
#define OUT 0   // outside a word

// program to print input one word per line

int main(void)
{
  int c, state;

  state = OUT;
  while ((c = getchar()) != EOF) {
    switch (state){
    case OUT:
        switch (c){
        case ' ': case '\n': case '\t':
        break;
        default:
            putchar(c);
            state = IN;
        }
    break;
    case IN:
        switch (c){
        case ' ': case '\n': case '\t':
            putchar('\n');
            state = OUT;
        break;
        default:
            putchar(c);
        }
    break;
    }        
  }
  return 0;
}
1 голос
/ 20 октября 2010

Смотрите, когда вы проверяете свой второй код

if (last != c) {

Вы проверяете не все условия. last может быть равно пробелу, табуляции или новой строке.Во всех таких случаях он не должен печатать новую строку.Давайте назовем набор этих трех специальных символов как X.

. Теперь при печати новой строки необходимо убедиться, что напечатанный символ last не приводит к установке X.Но вы проверяете это last!=current.Теперь текущим может быть пробел, табуляция или новая строка.Но это только одна ценность.Он не отвечает нашим потребностям, нашей цели.

Так что вместо этого замените его на

 if (last != ' ' && last != '\n' && last != '\t' ) {

Вы можете увидеть код здесь:

#include <stdio.h>

#define IN  1                   // inside a word
#define OUT 0                   // outside a word

// program to print input one word per line, corrected bug if there was
// more than one space between words to only print one \n

int main(void)
{
    int c, last, state;

    last = 0;  // We need it to make sure that a newline is not printed in case first
               // char is space, tab or new line.
    state = OUT;
    while ((c = getchar()) != EOF) {
        if (c == ' ' || c == '\n' || c == '\t') {
            // if (last != c)
            if (last != ' ' && last != '\n' && last != '\t' && last != 0 )
            {
                state = OUT;
                printf("\n");
            }
        } else if (state == OUT) {
            state = IN;
        }
        if (state == IN) {
            putchar(c);
        }
        last = c;
    }
    return 0;
}

РедактироватьИсправлена ​​ошибка, указанная в комментариях paxdiablo.

0 голосов
/ 21 декабря 2013
#include<stdio.h>

#define OFF 0
#define ON 1
main()
{
  int c,state=ON;
  while((c=getchar())!=EOF)
    {
      if(c=='\n'||c==' '||c=='\t')
       {
         if(state==OFF)putchar('\n');
         state=ON;
       }
      else if(state==ON)
       {
         putchar(c);
         state=OFF;
       }
      else if(state==OFF)
       {
         putchar(c);
       }
    }
}

Вот один из подходов к проблеме, который был использован выше:

Where, STE=Space, tab or enter.

<STE><WORD>---->TYPE<WORD>
<STE><STE>----->DO NOTHING
<WORD><SPACE>-->TYPE<WORD><ENTER/NEWLINE>
<WORD><WORD>--->TYPE<WORD>

Вы можете заменить и с ВКЛ и ВЫКЛ, как показано выше.

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