【问题标题】:Efficient String Parsing in CC 中的高效字符串解析
【发布时间】:2022-01-23 19:15:03
【问题描述】:

我正在为一个将 C 字符串作为输入的嵌入式系统实现一些 C getter/setter。

我需要解析出一些命令,例如:命令、选项、选项、选项。选项本身需要进一步解析。举个简单的例子

set_speed M1=10 M2=20,set_speed需要解析,那么每个token M1=10和M2=20都需要进一步解析。

不幸的是,strtok不能重复调用,如果可能的话问题就很简单了。

【问题讨论】:

  • 老式的方法是编写一个标记器(例如:使用 lex 或 flex),也可能是一个解析器(手动,或使用类似 yacc 的东西),但取决于您的特定语法命令可能更容易或更难。
  • 我认为在我的情况下,我可以执行以下操作,strtok 和 extract 命令,然后为每个后续令牌执行 strcmp 以查看前 N 个字节是否与选项匹配,然后最终将子字符串发送到 atof获得价值。想知道有没有更好的方法。我希望 strtok 是可重入的,但我想我可以使用 malloc 保存每个令牌,然后再次运行它。
  • 您不需要复制令牌,只需将strtok 返回的指针存储在数组中即可。我假设命令后面的选项数量有一些合理的上限。获得令牌指针数组后,您可以在每个指针上使用strtok 来进一步分解它。这样你就不需要strtok 重新进入。
  • strtok can not be repeatedly called unfortunately 可以。 (?), strtok and extract command, then for each following token do strcmp to see if the first N bytes match the option, then finally send the substring off to atof to get the value 正是这样做的。不要想“更好的方法”,随便做什么就行了。 I wish strtok was re-entrant 为什么需要重入?你有线程吗?您会同时多次调用strtok吗?
  • 问题很简单。做一个自定义函数。搜索下一个空间。检查路上的每个字符是否合法。使用strtol 将所有内容转换为整数。然后逐个字符地检查它们是否匹配,直到你点击=,然后再次搜索空格并转换。再次重复然后完成。

标签: c string parsing embedded


【解决方案1】:

使用strtok() 来拆分两个单词和选项是可能的,但有点痛苦。有 POSIX strtok_r(),它会更好,但这不在标准 C 中(但很容易自己编写......)。在大多数语言中,正则表达式是一个不错的选择,但它们又不在标准 C 中,只是在 POSIX 或第三方库(如 PCRE2)中。我想到了其他一些路线(例如sscanf(),或解析器生成器创建的例程(也许ragelre2c 值得探索,因为它们编译为嵌入在更大源文件中的C 代码并且不需要支持框架,但我对使用它们不是很熟悉)),但效率不高或不适合嵌入式环境。

但是,只需标准字符串搜索函数和一些指针操作,就可以一次性解析这样的字符串:

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

// Note: Destructively modifies its argument
void parse(char *str) {
  static const char *ws = " \t"; // Whitespace characters that separate tokens
  char *command = str;

  // Find the end of the first word
  str += strcspn(str, ws);
  if (*str) {
    *str++ = 0; // Terminate command
  }
  printf("Command: %s\n", command);

  while (*str) {
    // Skip leading whitespace
    str += strspn(str, ws);
    if (!*str) {
      // That was actually trailing whitespace at the end of the string
      break;
    }

    // Split at = sign
    char *option = str;
    str = strchr(str, '=');
    if (!str) {
      fputs("Missing = after option!\n", stderr);
      exit(EXIT_FAILURE);
    }
    *str++ = 0; // Terminate option

    // Parse the numeric argument
    char *valstr = str;
    double val = strtod(valstr, &str);
    if (valstr == str || !strchr(ws, *str)) {
      fprintf(stderr, "Non-numeric argument to %s!\n", option);
      exit(EXIT_FAILURE);
    }

    printf(" Option %s, value %f\n", option, val);
  }
}

int main(void) {
  char command_string[] = "set_speed M1=10 M2=20";
  parse(command_string);
  return 0;
}

例子:

$ gcc -g -O -Wall -Wextra -o demo demo.c
$ ./demo
Command: set_speed
 Option M1, value 10.000000
 Option M2, value 20.000000

【讨论】:

    【解决方案2】:

    getopt 是用于解析参数的标准 C 函数/库。这里有一个很好的例子......

    https://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html

    【讨论】:

    • 别这样,我的设备只支持 C 和 C++ 标准库。
    • 这很受欢迎。我不明白 getopt 是一个 GNU 函数。看看...stackoverflow.com/questions/10404448/…我认为它提供了几个解决方案。
    • @FourierFlux Don't have that, I only have C and C++ stdlib 你用的是什么编译器和编译器库?
    • getopt(3) 应该如何处理 OP 的命令?
    • 这与问题和嵌入式系统完全无关。
    猜你喜欢
    • 2021-05-08
    • 1970-01-01
    • 2017-03-02
    • 1970-01-01
    • 1970-01-01
    • 2013-10-23
    • 1970-01-01
    • 2011-02-15
    • 1970-01-01
    相关资源
    最近更新 更多