C strtok 解析复杂字符串

标签 c string strtok

你好,我在 C 中遇到了一个复杂的问题。我想拆分这个字符串(在这个例子中,我包含了所有可能的陷阱)

 "command1";"sleep 30; command2 -a ; command3";"command4="MyTest""

到:

command1
sleep 30; command2 -a ; command3
command4="MyTest"

字符串为“制表符”,元素之间用双引号和分隔; 我如何为此使用 strtok()

我尝试将 strtok() 与“;”一起使用像这样的分隔符:

   char mystring[1024]="\"command1\";\"sleep 30; command2 -a ; command3\";\"command4=\"MyTest\"\"";
   token = strtok(mystring, "\";\"");

   while( token != NULL ) {
      error(token);
      token = strtok(NULL, s);
   }

但我有这个输出:

command1
"sleep 30
command2 -a
command3"
"command4="MyTest""

感谢您的帮助

最佳答案

下面的示例按要求解析输入字符串。它需要进行一些调整才能完全满足您的需求(将 printf 替换为您的实际处理代码)。

要理解代码,请从描述字符串语法的顶部注释开始。然后转到 main - 使用调试器。

一些解释:

  • iss_t 是一个输入字符串流模拟。 iss_get_char 使用它从输入字符串中读取字符。
  • wschar_t 用于存储从输入流中读取的字符以及之前的空格。这是必需的,因为您没有指定 "; 之间是否有空格。它由 iss_get_wschariss_peek_wschar< 使用
  • iss_get_wschar 读取空格,直到找到非 ws 字符。
  • iss_peek_wschar除了不从流中提取字符外,与上面相同。
  • token_t 描述构成流的标记。
  • parser_get_token 从流中提取一个标记。这可能是最重要的功能。
  • parser_commands 从流中提取所有命令,它是解析器的主要功能。
  • parser_command 从流中提取命令。

可以测试代码here .

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

  /*
  commands:
    EOF
    |
    command commands

  command:
    command_begin string command_end

  string:
    anything but command_end

  command_begin:
    QUOTE

  command_end:
    QUOTE SEMICOLON
    |
    QUOTE EOF
  */

  struct iss_t
  {
    char* s;
    char* g;
  };
  typedef struct iss_t iss_t;

  char iss_get_char( iss_t* self )
  {
    if ( !*self->g )
      return 0;
    return *self->g++;
  }

  struct wschar_t
  {
    char c;
    char s[ 1024 ];
  };
  typedef struct wschar_t wschar_t;

  char iss_get_wschar( iss_t* self, wschar_t* r )
  {
    char* p = r->s;

    while ( isspace( *p++ = r->c = iss_get_char( self ) ) )
      ;
    *p = 0;
    return r->c;
  }

  char iss_peek_wschar( iss_t* self )
  {
    char* savedg = self->g;
    wschar_t t;
    iss_get_wschar( self, &t );
    self->g = savedg;
    return t.c;
  }

  enum token_t
  {
    tk_done,
    tk_beg,
    tk_end,
    tk_rest
  };
  typedef enum token_t token_t;

  struct parser_t
  {
    iss_t* iss;
    wschar_t wschar;
    token_t token;
  };
  typedef struct parser_t parser_t;

  token_t parser_get_token( parser_t* self )
  {
    iss_get_wschar( self->iss, &self->wschar );

    // if done
    if ( self->wschar.c == 0 )
      return self->token = tk_done;

    // not a quote
    if ( self->wschar.c != '\"' )
      return self->token = tk_rest;

    // it is quote: check the next token
    switch ( iss_peek_wschar( self->iss ) )
    {
    case 0:
    case ';':
      iss_get_wschar( self->iss, &self->wschar ); // eat
      return self->token = tk_end;
    default:
      return self->token = tk_beg;
    }
  }

  int parser_command( parser_t* self )
  {
    printf( "COMMAND: " );
    if ( self->token != tk_beg )
    {
      printf( "command begin expected" );
      return -1;
    }

    while ( parser_get_token( self ) == tk_rest || self->token == tk_beg )
      printf( self->wschar.s );

    if ( self->token != tk_end )
    {
      printf( "command end expected" );
      return -1;
    }

    printf( "\n" );

    return 0;
  }

  void parser_commands( parser_t* self )
  {
    while ( 1 )
    {
      switch ( parser_get_token( self ) )
      {

      case tk_done:
        return;

      default:
        if ( parser_command( self ) < 0 )
          return;

      };
    };
  }


  int main()
  {
    char* s = "\"command1\"; \"sleep 30; command2 -a ; command3\"; \"command4=\"MyTest\"\"";

    iss_t iss = { s, s };
    parser_t parser = { &iss };
    parser_commands( &parser );

    return 0;
  }

关于C strtok 解析复杂字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50721554/

相关文章:

Python 字符串是不可变的,那么为什么 s.split() 返回一个新字符串列表

Java 柠檬水计算器

c - c 中带有指针的 strtok 函数出现意外错误

c++ - 如何编译 C++ 代码并将其与已编译的 C 代码链接?

java - 在字符串声明中使用算术运算符时会发生什么?

c - 使用 strtok,最后一个标记带有一个行分隔符

c - 无法从 c 中的给定格式拆分输入字符串?

c - Julia 的消息处理程序

c - 如何执行这个缓冲区溢出?在Ubuntu中

将 R1C1 格式转换为 A1 格式