繁体   English   中英

使用Java处理负数时拆分数学表达式

[英]Split a mathematical expression while handling negative numbers with Java

我正在用Java开发表达式计算器。 我决定先编写一个代码以转换为后缀,然后再编写一个反向波兰表示法计算器。 到目前为止,我的计算器运行良好,可以处理任何表达式,包括运算符+ - * / %

但是,我遇到的问题是它使用空格input.split(" ")拆分了表达式,因此这意味着必须在输入表达式时输入( 4 + ( 2 * ( -2 - 1 ) ) ) * 1.5 input.split(" ") ( 4 + ( 2 * ( -2 - 1 ) ) ) * 1.5应该可以输入(4+(2*(-2-1)))*1.5

经过数小时的修改,我现在知道它不能运行正则表达式,但是它将能够编写一个for循环,一次遍历字符串的两个标记,如果它们都等于一个运算符,则可以假定第二个必须是一个运算符负值。 或者,如果方程式以运算符开头,那么它必须为负值吗? 像这样遍历字符串,直到第二个运算符到达表达式的末尾?

这是我一直试图尝试的一些代码,但是由于我对编程还是很陌生,所以似乎无法使其正常工作。

String expression = "(4+(2*(-2--16)))*-1.5";
ArrayList<String> tokens = new ArrayList<String>();
String orig = null;
String regex = "[-+/*()]+";
String first = Character.toString(expression.charAt(0));
tokens.add(first);
for (int i = 0; i < expression.length(); i++) {
    char x = expression.charAt(i);
    String a = Character.toString(x);
    if (i >= 1){    //Check i is greater than or equal to 1
        char y = expression.charAt(i-1);
        String b = Character.toString(y);
        if(b.matches(regex) && x == '-'){
            orig = a;
        }else if(orig != null && orig.equals("-")){
            System.out.println(orig + a);
            tokens.add(orig + a);
            orig = null;
        }else{
            tokens.add(a);
        }
    }
}
for(String t:tokens){
    System.out.print(t+" ");
}

感谢您的帮助,Ciaran。

编辑:

我的问题是我该如何编写一种拆分数学表达式的方法,该方法在拆分时可以区分出作为二进制运算符的“-”和作为一元运算符的“-”? 我是否对字符串进行迭代并比较两个标记的想法正确? – Ciaran Ashton 6分钟前

我要实现的目标是将String expression = (4+(2*(-2-1)))转换为String[] expression = (, 4, (, 2, *, (, -2, -, 1, ), ), )

这对于适当的解析器生成器来说是一项工作。 Java世界中最著名的是JavaCCAntlr 我喜欢将JFlex与JavaCC搭配使用。

它们的好处是,您可以根据上下文为令牌赋予不同的含义。 因此,减号在一个地方可能意味着一件事,而在另一地方可能意味着另一件事。

使用解析器是更好的解决方案,但是要按照您的要求回答您的问题,您可以使用此正则表达式,它几乎可以完成您想要的操作(不是100%,但是很接近):

(?<=[\(\)\+\-*\/\^A-Za-z])|(?=[\(\)\+\-*\/\^A-Za-z])

因此,您将不得不对其进行转义并像这样使用它:

String input = ...;
String temp[] = input.split("(?<=[\\(\\)\\+\\-*\\/\\^A-Za-z])|(?=[\\(\\)\\+\\-*\\/\\^A-Za-z])");
System.out.println(Arrays.toString(temp));

输入:

7+4-(18/3)/2a^222+1ab

输出:

[7, +, 4, -, (, 18, /, 3, ), /, 2, a, ^, 222, +, 1, a, b]

在这里查看实际操作:
http://rubular.com/r/uHAObPwaln
http://ideone.com/GLFmo4

这可能是解决您的问题的方法,尽管我尚未在各种数据上进行全面测试,但方法是-每当一元运算符出现在expression(全括号表达式)中时,它都将以'('开头,并在其后一个数字。

    String expression = "(4+(2*(-2-1)))*1.5";
    List<String> tokens = new ArrayList<String>();
    String prev = null;
    int c = 0;
    for (int i = 0; i < expression.length(); i++) {
        char x = expression.charAt(i);
        String a = Character.toString(x);
        if (i >= 1 && expression.charAt(i - 1) == '(' && x == '-') {
            prev = a;
        } else {
            if (prev != null && prev.equals("-")) {
                tokens.add(prev + a);
                prev = null;
            } else {
                tokens.add(a);
            }
            c++;
        }
    }

这是一个仅使用正则表达式的版本。 它与您的样本输入匹配,但不能处理将一元运算符放在括号前面或嵌套多个一元运算符(例如“ --1”)的情况:

// expression that matches standard Java number formats
// such as 1234, 12.5, and 1.3E-19
String number = "\\d+(?:\\.\\d+(?:(?:E|e)-?\\d+)?)?";
// expression that matches : 
// number
// number with unary operator (deemed unary if preceded by (,-,+,/, or *)
// (,),-,+,/, or *
String token = "(" + number + "|(?<=[(-+/*])-" + number + "|[-+/*()])?";
Pattern p = Pattern.compile(token);
Matcher m = p.matcher("(4+(2*(-2-1)))*1.5");
while (m.find()) {
  System.out.println(m.group(0));
}

好吧,毕竟在我的指导下,我创建了一个方法,该方法将采用-1+2(4+(2*(-2--1)))*-1.5并将其拆分为一个数组,例如[-1, +, 2, (, 4, +, (, 2, *, (, -2, -, -1, ), ), ), *, -1.5]

该方法的工作方式是使用正则表达式拆分输入String。 使用正则表达式,我可以拆分所有数字和运算符。 尽管这很棒,但它无法处理负值。 使用正则表达式它总是看到-二元运算符。 我需要将其视为一元运算符,以便它可以理解它是负值。 所以我要做的是将每个运算符与其后的字符串进行比较。 如果这也是一个运算符,我知道第二个是一元运算符。 然后,我还必须输入if语句,以了解第一个值是否为-以及是否知道那是一元运算符。

到目前为止,这是代码。 我敢肯定,有一种使用解析器进行此操作的简便方法,我只是无法将其包裹住。

import java.util.ArrayList;
import java.util.Arrays;


public class expSplit {

    public String[] splitExp(String theexp){
        ArrayList<String> tokens = new ArrayList<String>();
        //System.out.println(theexp);
        String expression = theexp.replaceAll("\\s+", "");
        //System.out.println(expression);
        String tem[] = expression.split("(?<=[-+*/%(),])(?=.)|(?<=.)(?=[-+*/%(),])");
        ArrayList<String> temp = new ArrayList<String>(Arrays.asList(tem));
        String orig = null;
        String regex = "[-+/%*]+";
        String first = temp.get(0);
        tokens.add(first);
        String secound = temp.get(1);
        if(first.equals("-")){
            tokens.remove(0);
            tokens.add(first+secound);
        }
        for (int i = 0; i < temp.size(); i++) {
            String a = temp.get(i);
            if (i >= 1){
                String b = temp.get(i-1);
                if(b.matches(regex) && a.matches("[-+]+")){
                    String c = temp.get(i-2);
                    if(c.matches("[-+]+")){
                        //System.out.println("MATCH");
                        break;
                    }else{
                        //System.out.println("NO MATCH");
                        orig = a;
                    }
                }else if(orig != null && orig.equals("-")){
                    tokens.add(orig + a);
                    orig = null;
                }else{
                    tokens.add(a);
                }
            }
        }
        if(first.equals("+")){
            tokens.remove(0);
        }
        if(first.equals("-")){
            tokens.remove(1);
        }
        String[]tokenArray = new String[tokens.size()];
        tokenArray = tokens.toArray(tokenArray);
        //System.out.print(tokens);
        return tokenArray;
    }
}

感谢您的帮助,Ciaran

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM