正则表达式字符串拆分将一个字符优先于另一个字符

时间:2019-01-04 11:47:37

标签: java regex

我知道有很多正则表达式帖子,但是我找不到确切的需求。我正在创建一个计算器应用程序,为此我需要一个方程式,需要根据该方程式中存在的运算符对它们进行标记。

示例:

“ 123x849-302 + 450”-> [“ 123”,“ 849”,“ 302”,“ 450”]

“ 124x(145 + 301)x402 +(-402)”-> [“ 124”,“ 145 + 301”,“ 402”,“-402”]

“ 124x((234 + 403)/ 354))+(-21)”-> [“ 124”,“(234 + 403)/ 354”,“ -21”]

基本上,如果有括号,我需要将令牌放入括号内,否则只需根据运算符进行拆分。

我对正则表达式非常不好,并且只了解基本知识。我不知道如何在正则表达式中包含括号,而现在,我所拥有的只是这个:

String delim = "[x+/-]";
String[] tokens = equation.toString().split(delim);

因为等式是StringBuilder,所以toString存在。

2 个答案:

答案 0 :(得分:1)

我认为正则表达式不是正确的工具。我不知道最终目标是什么,但是如果您只需要按问题中的表达式进行拆分,则可以尝试如下操作:

private static List<String> splitExpr(String expr) {
    List<String> result = new ArrayList<>();
    StringBuilder buf = new StringBuilder();
    int level = 0;
    int st = 0;
    for (char c: expr.toCharArray()) {
        if (level > 0) {
            // we're in a subexpression
            if (c == '(') {
                ++level;
            } else if (c == ')') {
                --level;
            }
            if (level == 0) {
                result.add(buf.toString());
                st = 2;
            } else {
                buf.append(c);
            }
        } else {
            switch (st) {
                case 0:
                    // initial state
                    if (Character.isDigit(c)) {
                        // first digit of a number
                        buf.setLength(0);
                        buf.append(c);
                        st = 1;
                    } else if (c == '(') {
                        // beginning of a subexpression
                        buf.setLength(0);
                        ++level;
                    } else {
                        // error: ignore unexpected character
                    }
                    break;
                case 1:
                    // inside a number
                    if (Character.isDigit(c)) {
                        // next digit
                        buf.append(c);
                    } else if (c == '+' || c == '-' || c == 'x' || c == 'X'
                            || c == '/') {
                        // operator; the number is finished, add it to the list
                        result.add(buf.toString());
                        st = 0;
                    } else {
                        // error: ignore unexpected character
                    }
                    break;
                case 2:
                    // after a subexpression
                    if (c == '+' || c == '-' || c == 'x' || c == 'X'
                            || c == '/') {
                        st = 0;
                    } else {
                        // error: ignore unexpected character
                    }
                    break;
            }
        }
    }
    if (level == 0 && st == 1) {
        // in a number at the end of string: add the number to the list
        result.add(buf.toString());
    }
    return result;
}

为您的示例:

123x849-302+450: [123, 849, 302, 450]
124x(145+301)x402+(-402): [124, 145+301, 402, -402]
124x((234+403)/354))+(-21): [124, (234+403)/354, -21]

答案 1 :(得分:1)

“常规”语法的概念是一个学术概念。 “正则表达式”的正确命名是:它们可以解析任何“正则”语法,但是不能用于解析非正则语法。

让我们将“基本数学”定义为数字,4个运算符:+-*/和括号的组合。

“基础数学”是不常规的

因此,无法使用正则表达式对其进行解析。

您想要的是一个可以打开此解析器的解析器:

a+x*y+(b-c)*e

进入此数据结构:

          PLUS
      /           \
    PLUS          TIMES
  /     \         /     \
a      TIMES    MINUS   e
      /   \    /  \
      x   y    b   c

各种解析器技术可以,例如递归下降或packrat(例如,使用grappa / parboiled解析器库),以及各种基于LALR和LL(k)的解析技术,例如ANTLR。通常,这些都是非常复杂的技术。也许对于这种琐碎的事情,您可以为此编写自己的基于递归下降的解析。

但是,回到您的原始问题,如果您想将a+x*y+(b-(g+h))*e分解为:['a','x','y','(b-(g + h))', 'e'],这只是您需要的一部分,因为现在您仍然需要弄清楚如何处理'(b-(g + h))'节点,正则表达式根本无法做到这一点:您想要正则表达式以将(前面的开头b作为括号块的开始,然后....您的正则表达式必须计算开头括号的数量,然后找到尽可能多的结尾括号并忽略这些,然后在那些获胜之后的结尾部分。因此,此正则表达式:

String elementPattern = "(\\([^\\)]+\\)|[^-+*/\\(\\)]+)";
Pattern p = Pattern.compile("^\\s*" + elementPattern + "(\\s*[-+*/]\\s*" + elementPattern + ")*$");
乍一看似乎可以完成工作的

实际上并不能完成工作:它将停止考虑两个封闭括号的 FIRST 中的(b-(g+h))部分,因此不匹配。它需要停在第二个位置,但是正则表达式没有任何办法,因为那不是“正则”。