用C标记字符串?

我正在研究用C编写的计算器的终端解析器。我无法弄清楚如何连接运算符之间的所有数字以将它们放入数组中。

例如,如果输入(命令行参数)是“ 4+342 ”,则理想情况下input[] = {"4", "+", "342"}

到目前为止,这是我的代码。 我包括

 typedef char * string; int main(int argc, char *argv[]) { string inputS = argv[1]; string input[10]; string temp; printf("%s\n", inputS); int i; int len = strlen(inputS); printf("parsed:\n"); for(i = 0; i < len; inputS++, i++) { if(isdigit(*inputS)) { printf("%c",*inputS); } else { printf("\n%c\n",*inputS); } } printf("\n"); return 0; } 

如果它以./calc 4+5-546运行,它将输出:

 4 + 5 - 546 

那么将每一行放入自己的arrays插槽的最简单方法是什么?

试试这个尺码……

 #include  #include  typedef char * string; int main(int argc, char *argv[]) { string inputS = argv[1]; string input[50]; /* Up to 50 tokens */ char buffer[200]; int i; int strnum = 0; char *next = buffer; char c; if (argc != 2) { fprintf(stderr, "Usage: %s expression\n", argv[0]); return 1; } printf("input: <<%s>>\n", inputS); printf("parsing:\n"); while ((c = *inputS++) != '\0') { input[strnum++] = next; if (isdigit(c)) { printf("Digit: %c\n", c); *next++ = c; while (isdigit(*inputS)) { c = *inputS++; printf("Digit: %c\n", c); *next++ = c; } *next++ = '\0'; } else { printf("Non-digit: %c\n", c); *next++ = c; *next++ = '\0'; } } printf("parsed:\n"); for (i = 0; i < strnum; i++) { printf("%d: <<%s>>\n", i, input[i]); } return 0; } 

鉴于该程序被称为tokenizer和命令:

 tokenizer '(3+2)*564/((3+4)*2)' 

它给了我输出:

 input: <<(3+2)*564/((3+4)*2)>> parsing: Non-digit: ( Digit: 3 Non-digit: + Digit: 2 Non-digit: ) Non-digit: * Digit: 5 Digit: 6 Digit: 4 Non-digit: / Non-digit: ( Non-digit: ( Digit: 3 Non-digit: + Digit: 4 Non-digit: ) Non-digit: * Digit: 2 Non-digit: ) parsed: 0: <<(>> 1: <<3>> 2: <<+>> 3: <<2>> 4: <<)>> 5: <<*>> 6: <<564>> 7: <> 8: <<(>> 9: <<(>> 10: <<3>> 11: <<+>> 12: <<4>> 13: <<)>> 14: <<*>> 15: <<2>> 16: <<)>> 

最简单的解决方案是使用像flex之类的工具来生成词法分析器并让它完成将输入分解为标记的工作(尽管flex期望其输入来自文件流,而不是字符数组)。

由于以下几个原因, strtok()不是一个好的解决方案:

  • 它会覆盖您可能希望保留以供以后使用的输入;
  • 它是一种powershell工具,不能很好地处理形状错误的输入;
  • 如果使用算术运算符作为标记分隔符,则运算符本身将被破坏。

通常的解决方案是编写一个状态机(这基本上就是flex为你做的)。 这是一个非常快速的脏(强调脏)示例:

 #include  #include  #include  #include  /** * Read from a string specified by source, updating the pointer as we go. * We're assuming that token points to a buffer large enough to hold * our largest token; ideally, you would want to pass the length of the * target buffer and check against it, but I'm leaving it out for brevity. * * Tokens are either integers (strings of digits) or operators. * * Return 1 if we successfully read a token, 0 if we encountered an unexpected * character, and EOF if the next character is the end of the input string. */ int getToken(char **source, char *token) { enum {START, DIGIT, ERROR, DONE} state = START; size_t i = 0; char *operators="+-*/"; if (**source == 0) // at end of input return EOF; while (**source != 0) { switch(state) { /** * Initial state for this call. */ case START: if (isdigit(**source)) { state = DIGIT; token[i++] = *(*source)++; // append the digit to the token } else if (strchr(operators, **source) != NULL) { state = DONE; token[i++] = *(*source)++; // add the operator to the token token[i++] = 0; // and terminate the string } else if (isspace(**source)) { (*source)++; // ignore whitespace } else { /** * We've read something that isn't a digit, operator, or * whitespace; treating it as an error for now. */ state = ERR; } break; /** * We've read at least one digit. */ case DIGIT: if (isdigit(**source)) { token[i++] = *(*source)++; // append next digit to token } else { /** * We've read a non-digit character; terminate the token * and signal that we're done. */ token[i++] = 0; state = DONE; } break; case DONE: return 1; break; case ERR: return 0; break; } } return 1; } int main(int argc, char **argv) { char token[20]; char *input = argv[1]; for (;;) { int result = getToken(&input, token); if (result == 1) printf("%s\n", token); else if (result == 0) { printf("Bad character '%c'; skipping\n", *input); input++; } else if (result == EOF) { printf("done\n"); break; } } return 0; } 

为什么(*source)++而不是*source++source++ ? 我不想更新source ,我想更新source ,所以我必须应用++ 之前取消引用指针。 表达式*(*source)++基本上转换为“给我表达*source指向的字符的值,然后更新*source的值”。

– > MAN STRCAT

 #include  #include  #include  int main (int argc, const char **argv) { char *toto_str = "Toto"; char *is_str = "Is"; char *awesome_str = "Awesome"; char *final_str; size_t i; i = strlen(toto_str); i += strlen(is_str); i += strlen(awesome_str); final_str = malloc((i * sizeof(char)) + 1); strcat(final_str, toto_str); strcat(final_str, is_str); strcat(final_str, awesome_str); printf("%s", final_str); free(final_str); return 0; } 

strsep在这里是一个不错的选择 – 抓住令牌,然后决定你想用它做什么……

char * string =“(3+(5 + 6)/ 8)”

char 令牌; while((token = strsep(&string,“(+ / )”))){//存储令牌…如果它不是(或)或空格}

这里 – 令牌将被处理类似于Java / C#中的Split()。 这会在处理字符串时破坏字符串 – 但是,使用正确的分隔符 – 事情会很好:)

听起来你想看看标准的strtokfunction。

这会给你一个想法:

 #include  #include  main(int argc, char *argv[]) { printf("\nargv[1]: %s",argv[1]); char *p; p = strtok(argv[1],"+"); printf("\np: %s", p); p = strtok(NULL,"+"); printf("\np: %s", p); p = strtok(NULL,"+"); printf("\np: %s", p); printf("\n"); } 

这只是一个示例代码,演示了如何仅使用附加案例来完成它。
了解此代码的主要概念并将其应用于您的代码中。
示例输出:

 ./a.out 5+3+9 argv[1]: 5+3+9 p: 5 p: 3 p: 9 

同样,我只是在展示“+”标志。 你可能想检查p直到它为NULL,然后继续下一个操作,比如减法,然后乘法,然后除法。