表达式求值:
30+3*(4-2.3)-3
这个式子,请问该怎么正确分解成为运算符和操作数?
我有个基本想法是:用DataInputStream来读一个byte,判断是否是数字,如果是,则放回流里面,然后以double形式重新读入一个。如果是字符,则是正常操作符。
如此直至读到末尾。
但这样做,我不知道怎么样把已经读入的字符放回流里面。请教大家一个思路,谢谢!

解决方案 »

  1.   

    可以使用Pushback流,它将字符或字节回退至流中.
    使用这个类:PushbackInputStream 中的方法read()!
      

  2.   

    pushbackInputStream有一个unread方法 可以把字节推回流的前端
      

  3.   

    TO:Greek618 你的想法很好,这样估计就是一种实现了
    TO:believefym 对,不过运算符当然包括左右括号谢谢两位
    再看下有没有别的完全不同的思路。
    其实还有scanner等类可以使用,但我不太清楚
      

  4.   

    是要这样的结果吗?String s = "30+3*(4-2.3)-3";
    String regex = "(?<=[+/*()-])|(?=[+/*()-])";
    String[] ss = s.split(regex);for (int i = 0; i < ss.length; i++)
    {
    System.out.println(ss[i]);
    }
      

  5.   

    接分!! 我以前做过这个! 给你一个类! 直接将表达式计算出值!
    package TAP;import java.util.Stack;
    import java.lang.Character;
    /**
     * Reverse Polish Notation
     *  算术逆波兰表达式.生成.
     * @author ewa26
     *
     */
        public  class SimpleRPN
        {
            private SimpleRPN() { }
            
            @SuppressWarnings("unchecked")
    private static String BuildingRPN(String s)
            {
                StringBuilder sb = new StringBuilder(s);
                Stack sk = new Stack();
                StringBuilder re = new StringBuilder();
                char c = ' ';
                //sb.Replace(" ","");//一开始,我只去掉了空格.后来我不想不支持函数和常量能滤掉的全OUT掉.
                for (int i = 0; i < sb.length(); i++)
                {
                    c = sb.charAt(i);
                if (Character.isDigit(c))//数字当然要了.
                        re.append(c);
                    //if(char.IsWhiteSpace(c)||char.IsLetter(c))//如果是空白,那么不要.现在字母也不要.
                    //continue;
                    switch (c)//如果是其它字符...列出的要,没有列出的不要.
                    {
                        case '+':
                        case '-':
                        case '*':
                        case '/':
                        case '%':
                        case '^':
                        case '!':
                        case '(':
                        case ')':
                        case '.':
                            re.append(c);
                            break;
                        default:
                            continue;
                    }
                }
                sb = new  StringBuilder(re.toString());
                //#region 对负号进行预转义处理.负号变单目运算符求反.
                for (int i = 0; i < sb.length() - 1; i++)
                    if (sb.charAt(i) == '-' && (i == 0 || sb.charAt(i - 1) == '('))
                     sb.setCharAt(i, '!');//字符转义.
               // #endregion
               // #region 将中缀表达式变为后缀表达式.
      

  6.   

    re = new StringBuilder();
                for (int i = 0; i < sb.length(); i++)
                {
                    if (Character.isDigit(sb.charAt(i)) ||sb.charAt(i) == '.')//如果是数值.
                    {
                        re.append(sb.charAt(i));//加入后缀式
                    }
                    else if (sb.charAt(i) == '+'
                     || sb.charAt(i) == '-'
                     || sb.charAt(i) == '*'
                     || sb.charAt(i) == '/'
                     || sb.charAt(i)== '%'
                     || sb.charAt(i) == '^'
                     || sb.charAt(i) == '!')//.
                    {
                     //   #region 运算符处理
                        while (sk.size() > 0) //栈不为空时 
                        {
                            c = sk.pop().toString().charAt(0); //将栈中的操作符弹出.
                            if (c == '(') //如果发现左括号.停.
                            {
                                sk.push(c); //将弹出的左括号压回.因为还有右括号要和它匹配.
                                break; //中断.
                            }
                            else
                            {
                                if (Power(c) < Power(sb.charAt(i)))//如果优先级比上次的高,则压栈.
                                {
                                    sk.push(c);
                                    break;
                                }
                                else
                                {
                                    re.append(' ');
                                    re.append(c);
                                }
                                //如果不是左括号,那么将操作符加入后缀式中.
                            }
                        }
                        sk.push(sb.charAt(i)); //把新操作符入栈.
                        re.append(' ');
                     //   #endregion
                    }
                    else if (sb.charAt(i) == '(')//基本优先级提升
                    {
                        sk.push('(');
                        re.append(' ');
                    }
                    else if (sb.charAt(i) == ')')//基本优先级下调
                    {
                        while (sk.size() > 0) //栈不为空时 
                        {
                            c = sk.pop().toString().charAt(0); //pop Operator 
                            if (c != '(')
                            {
                                re.append(' ');
                                re.append(c);//加入空格主要是为了防止不相干的数据相临产生解析错误.
                                re.append(' ');
                            }
                            else
                                break;
                        }
                    }
                    else
                        re.append(sb.charAt(i));
                }
                while (sk.size() > 0)//这是最后一个弹栈啦.
                {
                    re.append(' ');
                    re.append(sk.pop());
                }
               // #endregion            re.append(' ');
                return FormatSpace(re.toString());//在这里进行一次表达式格式化.这里就是后缀式了.
            }        /// <summary>
            /// 算术逆波兰表达式计算.
            /// </summary>
            /// <param name="s"></param>
            /// <returns></returns>
            @SuppressWarnings("unchecked")
    public static String ComputeRPN(String s)
            {            String S = BuildingRPN(s);
                String tmp = "";
                Stack sk = new Stack();
                char c = ' ';
                StringBuilder Operand = new  StringBuilder();
                double x, y;
                for (int i = 0; i < S.length(); i++)
                {
                    c = S.charAt(i);
                    if (Character.isDigit(c) || c == '.')
                    {//数据值收集.
                        Operand.append(c);
                    }
                    else if (c == ' ' && Operand.length() > 0)
                    {
                       // #region 运算数转换
                        try
                        {
                            tmp = Operand.toString();
                            if (tmp.startsWith("-"))//负数的转换一定要小心...它不被直接支持.
                            {//现在我的算法里这个分支可能永远不会被执行.
                                sk.push(-((double)Double.parseDouble(tmp.substring(1, tmp.length() - 1))));
                            }
                            else
                            {
                                sk.push(Double.parseDouble(tmp));
                            }
                        }
                        catch (Exception e) 
                        {
                            return "发现异常数据值.";
                        }
                        Operand = new StringBuilder();
                       // #endregion
                    }
                  
      

  7.   

    else if (c == '+'//运算符处理.双目运算处理.
                     || c == '-'
                     || c == '*'
                     || c == '/'
                     || c == '%'
                     || c == '^')
                    {
                      //  #region 双目运算
                        if (sk.size() > 0)/*如果输入的表达式根本没有包含运算符.或是根本就是空串.这里的逻辑就有意义了.*/
                        {
                            y = Double.parseDouble(sk.pop().toString());
                        }
                        else
                        {
                            sk.push(0);
                            break;
                        }
                        if (sk.size() > 0)
                            x = Double.parseDouble(sk.pop().toString());
                        else
                        {
                            sk.push(y);
                            break;
                        }
                        switch (c)
                        {
                            case '+':
                                sk.push(x + y);
                                break;
                            case '-':
                                sk.push(x - y);
                                break;
                            case '*':
                                sk.push(x * y);
                                break;
                            case '/':
                                sk.push(x / y);
                                break;
                            case '%':
                                sk.push(x % y);
                                break;
                            case '^':
                                //       if(x>0)
                                //       {我原本还想,如果被计算的数是负数,又要开真分数次方时如何处理的问题.后来我想还是算了吧.
                                sk.push(Math.pow(x, y));
                                //       }
                                //       else
                                //       {
                                //        double t=y;
                                //        string ts="";
                                //        t=1/(2*t);
                                //        ts=t.ToString();
                                //        if(ts.ToUpper().LastIndexOf('E')>0)
                                //        {
                                //         ;
                                //        }
                                //       }
                                break;
                        }
                      //  #endregion
                    }
                    else if (c == '!')//单目取反.)
                    {
                        sk.push(-(Double.parseDouble(sk.pop().toString())));
                    }
                }
                if (sk.size() > 1)
                    return "运算没有完成.";
                if (sk.size() == 0)
                    return "结果丢失..";
                return sk.pop().toString();
            }
            /// <summary>
            /// 优先级别测试函数.
            /// </summary>
            /// <param name="opr"></param>
            /// <returns></returns>
            private static int Power(char opr)
            {
                switch (opr)
                {
                    case '+':
                    case '-':
                        return 1;
                    case '*':
                    case '/':
                        return 2;
                    case '%':
                    case '^':
                    case '!':
                        return 3;
                    default:
                        return 0;
                }
            }
            
            private static String FormatSpace(String s)
            {
                StringBuilder ret = new StringBuilder();
                for (int i = 0; i < s.length(); i++)
                {
                    if (!(s.length() > i + 1 && s.charAt(i) == ' ' && s.charAt(i+1) == ' '))
                        ret.append(s.charAt(i));
                    else
                        ret.append(s.charAt(i));
                }
                return ret.toString();//.Replace('!','-');
            }
        }
      

  8.   

    TO laiwusheng(风清扬):先把这个想清楚,再问问星星怎么来的,其实星星来的很简单,只需要回到问题到点子上即可。
    TO Inhibitory() :你说这个大家都知道,要么我们转后缀表达式计算,要么双栈直接计算,现在的问题是怎么样来分解操作符和操作数。
    TO zsq007zsq007() :你的做法没有问题,一位一位的按照char作,然后将操作数组合,由string转换成double,不错。只是感觉比较繁琐。
    我认为这个问题在java中应该有更加简洁的解决方案,所以才提出这个问题的。
      

  9.   

    胡乱写了一个正则式,没仔细测试,
    根据find输出的group自己判断一下,+-*/()比较容易判断,其他的就当作数字
    String s = "-30+3*((4+-2.3)+-3)";
    String regex = "(?<=^)[\\+\\-]?\\d+(\\.\\d+)?|((?<=[+\\-\\*/])[+\\-\\*/]?\\d+(.\\d+)?)|[+\\-\\*/]|((?<=[\\(\\)])\\d+(\\.\\d+)?)|[\\(\\)]";
    Pattern p = Pattern.compile(regex);
    Matcher m = p.matcher(s);
    while(m.find()){
    System.out.println(m.group());
    }
      

  10.   

    To dropship(光荣与梦想) :把我忽略了-_-!!
      

  11.   

    believefym(feng) ( ) 信誉:100    Blog   加为好友  2007-06-09 20:17:51  得分: 0  
     
    大哥,不会你对java的类库熟悉的差不多了吧.....Matcher,Pattern这些东西见都没见过....汗一个
    不过程序好象正确的,就是不太明白原理...
      

  12.   

    TO:CrazyGou() 不好意思。你的方法我原来也想过,但是怎么获取操作符呢?
      

  13.   

    用那么麻烦的方法有必要么?
    采用切分流就OK了!
    StreamTokenizer类里这些功能都实现很大块了!
      

  14.   

    http://blog.csdn.net/CrazyGou/archive/2007/06/10/1646246.aspx
      

  15.   

    ding a 
    程序好长 都看不懂
      

  16.   

    请问正则表达式中的特殊构造中的
    (?=X) (?!X) (?<=X) (?<!X) (?>X)是什么意思?
    java的api中的解释看不明白
      

  17.   

    http://blog.csdn.net/CrazyGou/archive/2007/06/10/1646246.aspx
    楼主看了吗?分割字符串只一句正则:
    String[] words = str.split("(?<!^-?|[+/*()-]-)((?<=[+/*()-])|(?=[+/*()-]))");
    然后遍历words
    if (words[i].matches("-?\\d+|-?\\d+\\.\\d+")) {  //操作数
    ...
    }
    else {  //操作符
    ...
    }
      

  18.   

    正则表达式。去看看javacc。下面是javacc中语法分析的正则表达式定义:
    SKIP :
    {
      " "
    | "\t"
    | "\n"
    | "\r"
    | <"//" (~["\n","\r"])* ("\n"|"\r"|"\r\n")>
    | <"/*" (~["*"])* "*" (~["/"] (~["*"])* "*")* "/">
    }TOKEN : /* LITERALS */
    {
      < INTEGER_LITERAL:
            <DECIMAL_LITERAL> (["l","L"])?
          | <HEX_LITERAL> (["l","L"])?
          | <OCTAL_LITERAL> (["l","L"])?
      >
    |
      < #DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* >
    |
      < #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
    |
      < #OCTAL_LITERAL: "0" (["0"-"7"])* >
    }TOKEN : /* IDENTIFIERS */
    {
      < IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)* >
    |
      < #LETTER: ["_","a"-"z","A"-"Z"] >
    |
      < #DIGIT: ["0"-"9"] >
    }SimpleNode Start() : {}
    {
      Expression() ";"
      { return jjtThis; }
    }
    void Expression() : {}
    {
      AdditiveExpression()
    }void AdditiveExpression() : {}
    {
      MultiplicativeExpression() ( ( "+" | "-" ) MultiplicativeExpression() )*
    }void MultiplicativeExpression() : {}
    {
      UnaryExpression() ( ( "*" | "/" | "%" ) UnaryExpression() )*
    }void UnaryExpression() : {}
    {
      "(" Expression() ")" | Identifier() | Integer()
    }void Identifier() : {}
    {
      <IDENTIFIER>
    }void Integer() : {}
    {
      <INTEGER_LITERAL>
    }