用C标记字符串?

时间:2010-12-28 16:34:54

标签: c string parsing arguments char

我正在研究用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

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

6 个答案:

答案 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,然后继续下一个操作,比如减法,然后乘法,然后除法。