简体   繁体   English

如何在C中获取可变字符/字符串的输入?

[英]How to get input of variable chars/strings in C?

I have a problem where I need to get input from the user (command line), and it will either be in the format [char char char] or [char string], ie 3 chars or a char and a string. 我有一个需要从用户(命令行)获取输入的问题,它的格式为[char char char]或[char string],即3个字符或一个char和一个字符串。

I need the chars and string on their own with no white space etc, and it all has to be input on one line. 我需要自己的字符和字符串,没有空格等,并且所有这些都必须输入一行。

My current solution only works for 3 chars, but I am unsure of how to get it to work for both 3 chars or a char and a string. 我当前的解决方案仅适用于3个字符,但是我不确定如何使它同时适用于3个字符或一个字符和一个字符串。

This is my current code: 这是我当前的代码:

char move[3];

while(1){
    int i = scanf(" %c %c %c", &move[0], &move[1], &move[2]);

    if(i == 3){
        break;
    }
}       

If someone knows of how I can achieve what I want, I would be very grateful. 如果有人知道我如何实现自己想要的,我将非常感激。

A common way is to use something like this: 一种常见的方法是使用如下所示的内容:

char move[80];
char* tok = NULL;
if (fgets(move, 80, stdin) != NULL) {
    printf("Now you need to parse: %s\n", move);
    /* then split into tokens using strtok */
    tok = strtok(move, " "); 
    while (tok != NULL)
    {
        printf("Element: %s\n", tok);
        tok = strtok(NULL, " ");
    }
}

And then parse move using the C string handling functions. 然后使用C字符串处理函数解析移动。 You can use strtok to get your 2+ tokens. 您可以使用strtok获取2个以上的令牌。 If each element has strlen 1 then that is your 3 characters case and if first character is strlen 1 and second is 1+ length that is your second case. 如果每个元素的strlen为1,则这是3个字符的情况;如果第一个字符为strlen 1,第二个字符的长度为1+ length,则为第二种情况。

You could use a state machine to analyze and parse your input. 您可以使用状态机来分析和解析您的输入。 You define some number of states you can be in at any point while reading the input, and the transitions between states based on the input. 您可以定义在读取输入时随时可以处于的一些状态,以及基于输入的状态之间的转换。 For example: 例如:

  • expect_move1 - you haven't read any input yet, you're expecting to see a single non-whitespace character followed by whitespace; Expect_move1-您尚未阅读任何输入,您期望看到一个非空格字符,后接空格;
  • expect_move2_or_string - you've read your first move, and the next thing you expect to see is either another single character followed by whitespace *or* a sequence of non-whitespace characters followed by whitespace; Expect_move2_or_string-您已经阅读了第一步,并且接下来要看到的是另一个字符后跟空白*或*一系列非空白字符后跟空白;
  • expect_move3 - you've read a second single non-whitespace character followed by whitespace, and the next thing you expect to see is third single non-whitespace character followed by whitespace; Expect_move3-您已经阅读了第二个非空格字符,然后是空格,接下来您要看到的是第三个非空格字符,然后是空格;
  • done - you have either read 3 single non-whitespace characters *or* you have read 1 single non-whitespace character followed by a sequence of non-whitespace characters, and the only thing that should be left is whitespace; 完成 -您已经阅读了3个非空格字符*或*已经阅读了1个非空格字符,然后是一系列非空格字符,唯一剩下的就是空格;
  • error - you read something you didn't expect, and the input is improperly formatted. 错误 -您读了意想不到的内容,并且输入的格式不正确。

I womped up somewhat quick-n-dirty implementation, which handles various inputs as follows: 我用了一些快速n脏的实现,该实现处理各种输入,如下所示:

[fbgo448@n9dvap997]~/prototypes/state: ./state
a
..^
Bad input found at position 3
a b
....^
Bad input found at position 5
a b c
Read moves: a b c
a b c d
......^
Bad input found at position 7
a string
Read move: a string
a string c
.........^
Bad input found at position 10
a stringthatstoolongforourstringbuffer
......................^
Bad input found at position 23
some string
.^
Bad input found at position 2
a string followed by some junk
.........^
Bad input found at position 10

For your purposes, this is probably the definition of overkill and more involved than you need; 为了您的目的,这可能是过度杀伤的定义,比您需要的更多。 consider a badly-written example of how you might want to handle stuff like this in the future: 考虑一个写得不好的示例,该示例说明您将来可能希望如何处理此类事情:

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

/**
 *   State            Input                   New State
 *   -----            -----                   ---------
 *   exp_mv1          char + whitespace       exp_mv2_or_str
 *   exp_mv2_or_str   char + whitespace       exp_mv3
 *   exp_mv2_or_str   char seq + whitespace   done
 *   done             whitespace              done
 *
 *  Inputs that do not match the above lead to the error state.
 *
 */
int getInput( const char *input,     // input string
              size_t inputSize,      // length of input string
              char *moves,           // array to store moves
              size_t movesLen,       // length of moves array
              char *str,             // array to store string element
              size_t strLen,         // max length of string element array
              size_t *movesRead,     // number of moves read so far
              int *count)            // number of characters processed
{
  enum state { exp_mv1,              // expect a single char + whitespace
               exp_mv2_or_str,       // expect char + whitespace or string
               exp_mv3,              // expect char + whitespace
               done,                 // expect only whitespace until newline
               error }               // found something unexpected
    curState = exp_mv1;              // start in exp_mv1
  *count = 0;

  while ( *count < inputSize &&       // process input while we are not 
           curState != error &&       // at the end of the string and
           input[*count] &&           // we aren't in the error state
           input[*count] != '\n' )
  {
    switch( curState )
    {
      case exp_mv1:
        if ( !isspace( input[*count] ) )        // non-whitespace
        {
          if ( isspace( input[++(*count)] ) )   // followed by whitespace
          {
            moves[0] = input[((*count)++)-1];   // save the move
            (*movesRead)++;                     // update moves counter
            curState = exp_mv2_or_str;          // go to new state
          }
          else
          {
            curState = error;                   // bad input
          }
        }
        else
          (*count)++;                           // read whitespace, move
        break;                                  // to next character

      case exp_mv2_or_str:
        if ( !isspace( input[*count] ) )        // non-whitespace character
        {
          if ( isspace( input[++(*count)] ) )   // followed by whitespace
          {
            moves[1] = input[((*count)++)-1];   // save the move
            (*movesRead)++;                     // update moves counter
            curState = exp_mv3;                 // go to new state
          }
          else
          {
            size_t i = 0;                       // non-whitespace
            --(*count);                         // back up one character
            while ( i < strLen &&               // read characters until we
                    !isspace( input[*count] ) ) // run out of space or hit
            {                                   // a whitespace character
              str[i++] = input[(*count)++];     // and save to str
            }
            str[i] = 0;                         // 0-terminate str 

            if ( isspace( input[*count] ) )     // if current character is
              curState = done;                  // not whitespace, then the
            else                                // string was longer than
            {                                   // what we can store
              (*count)--;                       // previous character was first bad character
              curState = error;                 // go to error state
            }
          }
        }
        else
          (*count)++;                           // skip over whitespace character
        break;

      case exp_mv3:
        if ( !isspace( input[*count] ) )        // non-whitespace
        {
          if ( isspace( input[++(*count)] ) )   // followed by whitespace
          {
            moves[2] = input[((*count)++)-1];   // save the move
            (*movesRead)++;                     // update the moves counter
            curState = done;                    // go do done state
          }
          else
          {
            --count;                            // non-whitespace, previous char is bad character
            curState = error;                   // go to error state         
          }
        }
        else
          (*count)++;                           // skip whitespace character
        break;

      case done:
        if ( !isspace( input[*count] ) )        // non-whitespace character
        {
          curState = error;                     // go to error state
        }
        else
          (*count)++;                           // skip whitespace character

        break;

      case error:                               // no processing,
        break;
    }
  }
  return curState == done;
}

int main( void )
{
   char input[81];
   char moves[3];
   char str[21];
   size_t movesRead;
   int charsRead;

   while( fgets( input, sizeof input, stdin ) )
   {
     movesRead = 0;
     if ( getInput( input, strlen( input ), moves, sizeof moves, str, sizeof str, &movesRead, &charsRead ) )
     {
       if ( movesRead == 3 )
         printf( "Read moves: %c %c %c\n", moves[0], moves[1], moves[2] );
       else
         printf( "Read move: %c %s\n", moves[0], str );
     }
     else
     {
       const char *leader = ".....................................................................";

       fprintf( stderr, "%*.*s^\n", charsRead, charsRead, leader );
       fprintf( stderr, "Bad input found at position %d\n", charsRead+1 );
     }
  }

  return 0;
}

I apologize for posting a novel - you caught me at a weird time. 对于发布小说我深表歉意-您在一个奇怪的时间抓到了我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM