这是我的原始代码:
#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;
}
解决了这个问题,除非现在彼此相邻[空白] [标签],否则会打印换行符。
有人可以帮忙吗?
答案 0 :(得分:6)
您原始代码的问题在于,您将输出每个空白字符的换行符。您只想在从单词转换为非单词时执行此操作:
变化:
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;
}
答案 1 :(得分:2)
正如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;
}
答案 2 :(得分:1)
查看您何时签入第二个代码
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在评论中指出的错误。
答案 3 :(得分:0)
#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>
如上图所示,您可以替换ON和OFF。