我正在研究用C编写的计算器的终端解析器。 我无法弄清楚如何连接运算符之间的所有数字以将它们放入数组中。
例如,如果输入(命令行参数)是“4+342
”,
它理想情况下是input[] = {"4", "+", "342"}
。
到目前为止,这是我的代码。我包括<stdio.h>
,<stdlib.h>
和<ctype.h>
。
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
那么将每一行放入自己的阵列插槽的最简单方法是什么?
答案 0 :(得分:2)
试试这个尺寸......
#include <stdio.h>
#include <ctype.h>
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: <<)>>
答案 1 :(得分:2)
最简单的解决方案是使用flex之类的工具来生成词法分析器并让它完成将输入分解为标记的工作(尽管flex期望其输入来自文件流,而不是字符数组。)
由于以下几个原因, strtok()
不是一个好的解决方案:
通常的解决方案是编写一个状态机(这基本上就是flex为你做的)。这是非常 quick-n-dirty(强调脏)示例:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
/**
* 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
指向的内容,因此我必须在之前取消引用指针 { {1}}已应用。表达式++
基本上转换为“为我提供表达式*(*source)++
指向的字符的值,然后更新*source
的值”。
答案 2 :(得分:1)
- &GT; MAN STRCAT
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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;
}
答案 3 :(得分:1)
strsep在这里是一个不错的选择 - 抓住令牌,然后决定你想用它做什么......
char * string =“(3+(5 + 6)/ 8)”
char 令牌; while((token = strsep(&amp; string,“(+ / )”))){ //存储令牌......如果它不是(或)或空格 }
这里 - 令牌将被处理,类似于Java / C#中的Split()。这会在处理字符串时破坏字符串 - 但是,使用正确的分隔符 - 事情会很好:)
答案 4 :(得分:0)
听起来您想要查看标准的strtok
函数。
答案 5 :(得分:0)
这会给你一个想法:
#include <stdio.h>
#include <string.h>
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,然后继续下一个操作,比如减法,然后乘法,然后除法。