在没有数组的长序列中搜索模式字符串[关闭]

问题描述 投票:2回答:1

我想问一下如何使用getchar()在不同字符的长输入中搜索两种模式(例如RFMKCR和AWY)?

P.S不允许使用数组。谢谢!

c pattern-matching state-machine
1个回答
2
投票

这是状态机的完整代码,它从通用函数getchar1()获取输入。模式:AWYRFMKCR被认可和报告。

函数getchar1()只是从输入中获取char的任何函数的包装器。可以在里面使用getchar()scanf。由STOP定义的char终止输入处理。

这个问题的困难来自需要寻找两种模式的开头:AWYRFMKCR同时。我们可能被迫切换到寻找另一个模式中间的不同模式或重新同步。

给出了三个完整的解决方案

第一种解决方案使用递归。

第二种解决方案使用简单的goto结构,避免递归调用。这种方法对于这个特定问题非常有效。

注意:在C中通常不鼓励使用goto。尽可能使用breakcontinuereturn语句而不是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*                                                                                                                                                                                                                                        
© www.soinside.com 2019 - 2024. All rights reserved.