从C中的char数组中的'('和')'内部提取字符

时间:2015-11-22 14:59:24

标签: c arrays parsing char extract

我遇到了这个问题: 用户编写数学表达式,程序需要从中提取内部()ex的所有子表达式。 (x + 2)或(x +(y-2))。

例如,如果用户输入2-(5 +(x-6) - (y + 9)),程序应返回(x-6),(y + 9),(5 +(x-) 6) - (Y + 9))

这是我试过的。

#include<stdio.h>
int main()
{
    char a[100];
    int i=0,t,j=0;
    printf("enter math expression:\n");
    while( (a[i++]=getchar()) != '\n' && i < 100);
    a[i] = '\0';

  for (i=0; a[i]!='\0'; i++)
    {
        if (a[i]=='(')
        {   printf("found (\n");
            j++;
              while (a[i] !=')')
                printf("%c",a[i++]);

                printf("%c",a[i]);

4 个答案:

答案 0 :(得分:1)

由于您正在处理嵌套表达式,因此需要保留堆栈以匹配括号。理想情况下,你应该在循环内:

  1. 每当发现&#39;(&#39;,将字符串中的位置推入堆栈
  2. 当&#39;)&#39;找到,然后从堆栈弹出匹配的位置&#39;(&#39;。你有表达式的起始索引。
  3. 继续直到字符串完成
  4. 示例(x + (y+2))

    i == 0 -> '(' -> s.push(0);
    i == 1 -> 'x' 
    i == 2 -> '+'
    i == 3 -> '(' -> s.push(3);
    i == 4 -> 'y'
    i == 5 -> '+'
    i == 6 -> '2'
    i == 7 -> ')' -> s.pop() [3, 7] contains '(y + 2)'
    i == 8 -> ')' -> s.pop() [0, 8] contains '(x + (y+2))'
    

答案 1 :(得分:0)

在此上下文中,s为cstring。

由于在有效的数学表达式中,括号是平衡的,我们可以观察到,

    如果s [0]不是&#39;(&#39; ,则
  1. s + 1是平衡的
  2. 如果s [0]是&#39;(&#39;那么我们就在括号表达的开头。
  3. 在#1的情况下,我们不关心第一个角色。所以,我们可以设置s = s + 1并重新开始。 在#2的情况下,我们必须找到第一个字符的匹配结束。所以,我们把它分成两部分。匹配的表达式和尾部。两者都是有效的表达。所以,我们重新开始。

    int main()
    {
        char s[] = "2-(5+(x-6)-(y+9))";// s have to be modifiable.
    
        extractAndPrint(s, 0); // we are at start and 0 indicates balanced
    
        return 0;
    }
    

    现在,

    void extractAndPrint(char *s, int found)
    {
        if(s[0] == 0) return;//no more honey
        if(!found){ //so far balanced
            if(s[0] == '(') extractAndPrint(s+1, 1);// case 2
            else extractAndPrint(s+1, 0); //this is the case 1
        } else {//start of a expression
            char *t;
            //separates the end of current expression 
            //and the remaining part.
            mark_end(s, 0, &t);
            printf("(%s)\n", s);
            extractAndPrint(s, 0);//potentially contain more expression
            extractAndPrint(t, 0);//check past the previous exp
        }
    }
    

    我也喜欢这里的递归。它对我的思考少了。可以更优雅的方式实施。

    void mark_end(char *s, int c, char **t)
    {
        if(c == 0){
            if(s[0] == ')'){
                *t = s+1;
                *s = '\0';
            } else if(s[0] == '('){
                mark_end(s+1, c+1, t);
            } else {
                mark_end(s+1, c, t);
            }
        } else {
            if(s[0] == ')'){
                mark_end(s+1, c-1, t);
            } else if(s[0] == '('){
                mark_end(s+1, c+1, t);
            } else {
                mark_end(s+1, c, t);
            }
        }
    }
    

    输出:

    (5+(x-6)-(y+9))
    (x-6)
    (y+9)
    

答案 2 :(得分:0)

我建议您使用状态机,在您的情况下,此状态机应该合适:enter image description here

所以你的主要是一种开关盒,负责编写你的pop并推送功能并用一个好的结构代表你的堆

答案 3 :(得分:0)

您应该使用递归将字符串解析为括号树。以下示例说明如何执行此操作:

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

#define MAX_DATA 100

int mathexp(const char *exp, int start, int end)
{
  int i = start;
  while(i < (start + end) && exp[i] != ')') {
    if(exp[i] == '(') {
      i = mathexp(exp, i + 1, end) + 1;
    } else {
      i++;
    }
  }
  char subexp[i - start];
  memcpy(subexp, &exp[start], i - start);
  subexp[i - start] = '\0';
  printf("%s\n", subexp);
  return i;
}

int main(int argc, char *argv[])
{
  char input[MAX_DATA];
  printf("Enter a math expression: ");
  fgets(input, sizeof(input), stdin);
  input[strcspn(input, "\r\n")] = '\0'; // remove trailing \r\n
  mathexp(input, 0, strlen(input));
  return 0;
}

当你测试它时,你有:

Enter a math expression: 2-(5+(x-6)-(y+9))
x-6
y+9
5+(x-6)-(y+9)
2-(5+(x-6)-(y+9))