我知道有很多正则表达式帖子,但是我找不到确切的需求。我正在创建一个计算器应用程序,为此我需要一个方程式,需要根据该方程式中存在的运算符对它们进行标记。
示例:
“ 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存在。
答案 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))
部分,因此不匹配。它需要停在第二个位置,但是正则表达式没有任何办法,因为那不是“正则”。