简体   繁体   中英

Efficient algorithm for expression parser (Java)

I am trying to design an algorithm that can parse an expression in the form of a String. I want to be able to extract the operands and the operation from the given expression. Also, I want the algorithm to recognize bracket balance. No need for precedence of operations, as the input of the algorithm will include brackets if there are more than 1 binary operations. For unary operations, if a "-" appears before a bracket, it means the entire expression inside the respective brackets is the operand. Examples:

-parsing "a+b" gives "a" and "b" as operands and "+" as operation.
-parsing "(a/b) - (c*v)" gives "a/b" and "c*v" as operands and "-" as operation.
-parsing "((a/(b))) - (((c)*v))" gives the same result as above
-parsing "-a" gives operand as "a" and operation as "-"
-parsing "a + (-c/v)" gives "a" and "-c/v" as operands and "+" as operation
-parsing "-(c)" gives "c" is operand and "-" as operands
-parsing "(-(c))" gives same result as above

Thanks

Try this.

record Node(String name, Node left, Node right) {
    @Override
    public String toString() {
        return "Node[" + name
            + (left != null ? ", " + left : "")
            + (right != null ? ", " + right : "") + "]";
    }
}

and

static Node parse(String input) {
    return new Object() {
        int index = 0;

        int ch() { return index < input.length() ? input.charAt(index) : -1; }

        boolean eat(char expected) {
            while (Character.isWhitespace(ch())) ++index;
            if (ch() == expected) {
                ++index;
                return true;
            }
            return false;
        }

        Node factor() {
            Node node;
            boolean minus = eat('-');
            if (eat('(')) {
                node = expression();
                if (!eat(')'))
                    throw new RuntimeException("')' expected");
            } else if (Character.isAlphabetic(ch())) {
                node = new Node(Character.toString(ch()), null, null);
                ++index;
            } else
                throw new RuntimeException("unknown char '" + (char)ch() + "'");
            if (minus) node = new Node("-", node, null);
            return node;
        }

        Node expression() {
            Node node = factor();
            while (true)
                if (eat('*')) node = new Node("*", node, factor());
                else if (eat('/')) node = new Node("/", node, factor());
                else if (eat('+')) node = new Node("+", node, factor());
                else if (eat('-')) node = new Node("-", node, factor());
                else break;
            return node;
        }
    }.expression();
}

test:

static void testParse(String input) {
    System.out.printf("%-22s -> %s%n", input, parse(input));
}

public static void main(String[] args) {
    testParse("a+b");
    testParse("(a/b) - (c*v)");
    testParse("((a/(b))) - (((c)*v))");
    testParse("-a");
    testParse("-a + (-c/v)");
    testParse("-(c)");
    testParse("(-(c))");
}

output:

a+b                    -> Node[+, Node[a], Node[b]]
(a/b) - (c*v)          -> Node[-, Node[/, Node[a], Node[b]], Node[*, Node[c], Node[v]]]
((a/(b))) - (((c)*v))  -> Node[-, Node[/, Node[a], Node[b]], Node[*, Node[c], Node[v]]]
-a                     -> Node[-, Node[a]]
-a + (-c/v)            -> Node[+, Node[-, Node[a]], Node[/, Node[-, Node[c]], Node[v]]]
-(c)                   -> Node[-, Node[c]]
(-(c))                 -> Node[-, Node[c]]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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