我想问一下如何使用getchar()在不同字符的长输入中搜索两种模式(例如RFMKCR和AWY)?
P.S不允许使用数组。谢谢!
这是状态机的完整代码,它从通用函数getchar1()
获取输入。模式:AWY
和RFMKCR
被认可和报告。
函数getchar1()
只是从输入中获取char的任何函数的包装器。可以在里面使用getchar()
或scanf
。由STOP
定义的char终止输入处理。
这个问题的困难来自需要寻找两种模式的开头:AWY
和RFMKCR
同时。我们可能被迫切换到寻找另一个模式中间的不同模式或重新同步。
给出了三个完整的解决方案
第一种解决方案使用递归。
第二种解决方案使用简单的goto
结构,避免递归调用。这种方法对于这个特定问题非常有效。
注意:在C中通常不鼓励使用goto
。尽可能使用break
,continue
和return
语句而不是goto
是一种很好的编程风格。由于break
语句仅从循环的一个级别退出,因此从深层嵌套循环中退出循环可能需要goto
。
第三种解决方案不使用递归或goto
语句,并试图显示一种可以轻松适应不同模式的通用方法。
解决方案1)
#include <stdio.h>
#include <stdlib.h>
#define STOP '!'
int START(void);
int AWY(void);
int RFMKCR(void);
int END(void);
int getchar1 (void)
{
char in;
in = getchar(); // scanf ("%c", &in);
return in;
}
int START(void)
{
int c = getchar1 ();
if (c == 'A') return AWY();
if (c == 'R') return RFMKCR();
if (c == STOP) return END();
return 1;
}
int AWY(void) // A already found
{
int c = getchar1 ();
if (c == 'A') return AWY();
if (c == 'R') return RFMKCR();
if (c == STOP) return END();
if (c != 'W') return 1;
// W found
c = getchar1 ();
if (c == 'A') return AWY();
if (c == 'R') return RFMKCR();
if (c == STOP) return END();
if (c != 'Y') return 1;
// Y found
printf ("AWY found\n");
return 1;
}
int RFMKCR(void) // R already found
{
int c = getchar1 ();
if (c == 'A') return AWY();
if (c == 'R') return RFMKCR();
if (c == STOP) return END();
if (c != 'F') return 1;
// F found
c = getchar1 ();
if (c == 'A') return AWY();
if (c == 'R') return RFMKCR();
if (c == STOP) return END();
if (c != 'M') return 1;
// M found
c = getchar1 ();
if (c == 'A') return AWY();
if (c == 'R') return RFMKCR();
if (c == STOP) return END();
if (c != 'K') return 1;
// K found
c = getchar1 ();
if (c == 'A') return AWY();
if (c == 'R') return RFMKCR();
if (c == STOP) return END();
if (c != 'C') return 1;
// C found
c = getchar1 ();
if (c == 'A') return AWY();
if (c == STOP) return END();
if (c != 'R') return 1;
// R found
printf ("RFMKCR found\n");
return 1;
}
int END(void)
{
return 0;
}
int main ()
{
printf ("\n*start*\n");
while(START());
printf ("*the end*\n");
return 0;
}
解决方案2)
#include <stdio.h>
#include <stdlib.h>
#define STOP '!'
int START()
{
int c;
START:
c = getchar1 ();
if (c == 'A') goto AWY;
if (c == 'R') goto RFMKCR;
if (c == STOP) goto END;
goto START;
AWY: // A found
c = getchar1 ();
if (c == 'A') goto AWY;
if (c == 'R') goto RFMKCR;
if (c == STOP) goto END;
if (c != 'W') goto START;
// W found
c = getchar1 ();
if (c == 'A') goto AWY;
if (c == 'R') goto RFMKCR;
if (c == STOP) goto END;
if (c != 'Y') goto START;
// Y found
printf ("AWY found\n");
goto START;
RFMKCR: // R found
c = getchar1 ();
if (c == 'A') goto AWY;
if (c == 'R') goto RFMKCR;
if (c == STOP) goto END;
if (c != 'F') goto START;
// F found
c = getchar1 ();
if (c == 'A') goto AWY;
if (c == 'R') goto RFMKCR;
if (c == '!') goto END;
if (c != 'M') goto START;
// M found
c = getchar1 ();
if (c == 'A') goto AWY;
if (c == 'R') goto RFMKCR;
if (c == '!') goto END;
if (c != 'K') goto START;
// K found
c = getchar1 ();
if (c == 'A') goto AWY;
if (c == 'R') goto RFMKCR;
if (c == STOP) goto END;
if (c != 'C') goto START;
// C found
c = getchar1 ();
if (c == 'A') goto AWY;
if (c == STOP) goto END;
if (c != 'R') goto START;
// R found
printf ("RFMKCR found\n");
goto START;
END:
return 0;
}
int getchar1(void) // wraper around your input
{
char in;
in = getchar(); // or scanf ("%c", &in);
return in;
}
int main ()
{
printf ("*start*\n");
START();
printf ("*the end*\n");
return 0;
}
两种解决方案都产生相同的输出。
INPUT的输出:AAWY AAWWAWY RRRFMKCR A A WY AWRFMCR AAA!
*start*
AWY found
AWY found
RFMKCR found
*the end*
3)解决方案
/******************************************************************************
CLASSICAL STATE MACHINE APPROACH
- take a notice how the generic `next` function service transitions
- together with the `start` helper.
- `next` and `start` have the same functions signatures
- and can be replaced with a function pointers
The resulting code is more complicated than previous two examples.
However:
a) the input is taken only from one place (inside the while loop)
b) the generic nature of the code allows easy customization/
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#define STOP '!' // character chosen to stop processing
#define END 0
#define IDLE 1
#define START 2
#define AWY_A 3
#define AWY_W 4
#define AWY_Y 5
#define RFMKCR_R 6
#define RFMKCR_F 7
#define RFMKCR_M 8
#define RFMKCR_K 9
#define RFMKCR_C 10
#define RFMKCR_R_END 11
#define AWY_FOUND 12
#define RFMKCR_FOUND 13
#define TO_BE_CALCULATED 14
#define UNKNOWN_STATE 15
// we keep here the current state and next state to which we will transit
struct state_machine_state
{
int current_state;
int next_state;
unsigned int debug_flag;
};
int getchar1 (void);
int start(struct state_machine_state *p, int c, int current_state, int char_expected, int next_state);
int next(struct state_machine_state *p, int c, int current_state, int char_expected, int next_state);
int state_machine(struct state_machine_state *p, int c);
int processing(void);
int getchar1 (void)
{
int in;
in = getchar(); //char in = scanf ("%c", &in);
return in;
}
int next(struct state_machine_state *p, int c, int current_state, int char_expected, int next_state)
{
// This generic function provides transitions to the required states based on the input `c` character
// If c matches the expected character than we transition to known apriori next state
// If the input `c` does not match expected character then we re-start the hunt for patterns
if (c == char_expected)
{
if(p->debug_flag)
printf("++: c=%c cs=%d next=%d \n", c, p->next_state, next_state);
p->current_state = current_state;
p->next_state = next_state;
return next_state;
}
return ( start(p, c, current_state, c, TO_BE_CALCULATED) );
}
int start(struct state_machine_state *p, int c, int current_state, int char_expected, int next_state)
{
// We hunt for the following
// - start of the AWY pattern: 'A'
// - start of the RFMKCR pattern 'R'
// - special termination character (see: #define STOP )
// If none of the above is found than continue the hunt, we stay in the START state
switch(c)
{
case 'A': return( next(p, c, AWY_A, 'A', AWY_W) ); // == p->current_state = AWY_A; p->next_state = AWY_W; return AWY_W;
case 'R': return( next(p, c, RFMKCR_R, 'R', RFMKCR_F) ); // == p->current_state = RFMKCR_R; p->next_state = RFMKCR_F; return RFMKCR_F;
case STOP: return( next(p, c, END, STOP, END) ); // == p->current_state = END; p->next_state = END; return END;
default: return( next(p, c, START, c, START) ); // == p->current_state = START; p->next_state = START; return START;
}
}
int state_machine(struct state_machine_state *p, int c)
{
// state machine gets two inputs, pointer `p` to state_machine_state structure
// and current char `c` to be processed
switch (p->next_state)
{
// search for the beginning of the pattern:
case START: return( start(p, c, START, c, TO_BE_CALCULATED) ); // can return: AWY_W, RFMKCR_F, START, END
// process all expected transitions for the AWY pattern
// A->W->Y
case AWY_W: return( next(p, c, AWY_W, 'W', AWY_Y) ); // can return AWY_W
case AWY_Y: return( next(p, c, AWY_Y, 'Y', AWY_FOUND ) ); // can return AWY_FOUND
// process proper transitions for the RFMKCR pattern:
// R->F->M->K->C->R
case RFMKCR_F: return ( next(p, c, RFMKCR_F, 'F', RFMKCR_M) );
case RFMKCR_M: return ( next(p, c, RFMKCR_M, 'M', RFMKCR_K) );
case RFMKCR_K: return ( next(p, c, RFMKCR_K, 'K', RFMKCR_C) );
case RFMKCR_C: return ( next(p, c, RFMKCR_C, 'C', RFMKCR_R_END) );
case RFMKCR_R_END: return ( next(p, c, RFMKCR_R_END, 'R', RFMKCR_FOUND) ); // can retun RFMKCR_FOUND
default: printf ("UNKNOWN STATE! %d=\n", p->next_state); return( start(p,c,UNKNOWN_STATE,c,TO_BE_CALCULATED) ); // We should never come here!!!
}
}
int processing(void)
{
int c;
int next_state;
struct state_machine_state s;
// Init state machine:
s.current_state = IDLE;
s.next_state = START;
s.debug_flag = 0; // change to 1 if you need to see transitions
// --
while(1)
{
c = getchar1(); // may state machine designs like to have an input in one place
next_state = state_machine(&s,c); // our main state processor
// We service here special states:
switch(next_state) // s.next_state can be used as well
{
case AWY_FOUND:
printf("AWY found\n"); // we will continue search
next(&s, c, AWY_FOUND, 'Y', START);
break;
case RFMKCR_FOUND: // we will continue search
printf("RFMKCR found\n");
next(&s, c, RFMKCR_FOUND, 'R', START);
break;
case END:
next(&s, c, END, STOP, END);
return 0; // This state terminates processing
default:
// We are not interested in these states!
break;
}
}
return 0;
}
int main ()
{
printf ("*start*\n");
processing();
printf ("*the end*\n");
return 0;
}
OUTPUT:
*start*
AAWY A W Y RFMKCRR AWYY!
AWY found
RFMKCR found
AWY found
*the end*