从数学表达式中提取操作数的正则表达式

Kam*_*ood 6 java regex parsing mathematical-expressions

没有关于SO的问题解决了我的特殊问题.我对正则表达的了解很少.我正在使用Regex Class在Java中构建表达式解析器.我想从表达式中提取操作数,参数,运算符,符号和函数名称,然后保存到ArrayList.目前我正在使用这种逻辑

String string = "2!+atan2(3+9,2+3)-2*PI+3/3-9-12%3*sin(9-9)+(2+6/2)" //This is just for testing purpose later on it will be provided by user
List<String> res = new ArrayList<>();
Pattern pattern = Pattern.compile((\\Q^\\E|\\Q/\\E|\\Q-\\E|\\Q-\\E|\\Q+\\E|\\Q*\\E|\\Q)\\E|\\Q)\\E|\\Q(\\E|\\Q(\\E|\\Q%\\E|\\Q!\\E)) //This string was build in a function where operator names were provided. Its mean that user can add custom operators and custom functions 
Matcher m = pattern.matcher(string);
int pos = 0;
while (m.find()) 
{
    if (pos != m.start()) 
    {
        res.add(string.substring(pos, m.start()))
    }
    res.add(m.group())
    pos = m.end();
}
if (pos != string.length()) 
{
     addToTokens(res, string.substring(pos));
}
for(String s : res)
{
     System.out.println(s);
}
Run Code Online (Sandbox Code Playgroud)

输出:

2
!
+
atan2
(
3
+
9
,
2
+
3
)
-
2
*
PI
+
3
/
3
-
9
-
12
%
3
*
sin
(
9
-
9
)
+
(
2
+
6
/
2
)
Run Code Online (Sandbox Code Playgroud)

问题是现在Expression可以包含具有用户定义格式的Matrix.我希望在函数的情况下将每个Matrix视为操作数或参数.

输入1:

String input_1 = "2+3-9*[{2+3,2,6},{7,2+3,2+3i}]+9*6"
Run Code Online (Sandbox Code Playgroud)

输出应该是:

2
+
3
-
9
*
[{2+3,2,6},{7,2+3,2+3i}]
+
9
*
6
Run Code Online (Sandbox Code Playgroud)

输入2:

String input_2 = "{[2,5][9/8,func(2+3)]}+9*8/5"
Run Code Online (Sandbox Code Playgroud)

输出应该是:

{[2,5][9/8,func(2+3)]}
+
9
*
8
/
5
Run Code Online (Sandbox Code Playgroud)

输入3:

String input_3 = "<[2,9,2.36][2,3,2!]>*<[2,3,9][23+9*8/8,2,3]>"
Run Code Online (Sandbox Code Playgroud)

输出应该是:

<[2,9,2.36][2,3,2!]>
*
<[2,3,9][23+9*8/8,2,3]>
Run Code Online (Sandbox Code Playgroud)

我希望现在ArrayList应该包含每个索引处的每个操作数,运算符,参数,函数和符号.如何使用正则表达式实现所需的输出.不需要表达式验证.

m.c*_*era 3

我想你可以尝试这样的事情:

(?<matrix>(?:\[[^\]]+\])|(?:<[^>]+>)|(?:\{[^\}]+\}))|(?<function>\w+(?=\())|(\d+[eE][-+]\d+)|(?<operand>\w+)|(?<operator>[-+\/*%])|(?<symbol>.)
Run Code Online (Sandbox Code Playgroud)

演示版

元素在命名的捕获组中捕获。如果不需要,可以使用简短的:

\[[^\]]+\]|<[^>]+>|\{[^\}]+\}|\d+[eE][-+]\d+|\w+(?=\()|\w+|[-+\/*%]|.
Run Code Online (Sandbox Code Playgroud)


匹配\[[^\]]+\]|<[^>]+>|\{[^\}]+\}左括号 ( {,[<)、非类括号字符和右括号 ( }, ], >),因此如果没有嵌套的同类型括号,则没有问题。用Java实现:

public class Test {
    public static void main(String[] args) {
        String[] expressions = {"2!+atan2(3+9,2+3)-2*PI+3/3-9-12%3*sin(9-9)+(2+6/2)", "2+3-9*[{2+3,2,6},{7,2+3,2+3i}]+9*6",
        "{[2,5][9/8,func(2+3)]}+9*8/5","<[2,9,2.36][2,3,2!]>*<[2,3,9][23 + 9 * 8 / 8, 2, 3]>"};
        Pattern pattern = Pattern.compile("(?<matrix>(?:\\[[^]]+])|(?:<[^>]+>)|(?:\\{[^}]+}))|(?<function>\\w+(?=\\())|(?<operand>\\w+)|(?<operator>[-+/*%])|(?<symbol>.)");
        for(String expression : expressions) {
            List<String> elements = new ArrayList<String>();
            Matcher matcher = pattern.matcher(expression);
            while (matcher.find()) {
                elements.add(matcher.group());
            }
            for (String element : elements) {
                System.out.println(element);
            }
            System.out.println("\n\n\n");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

替代方案说明:

  • \[[^\]]+\]|<[^>]+>|\{[^\}]+\}- 匹配给定类型的左括号、不是该类型右括号的字符(不是右括号的所有字符)以及该类型的右括号,
  • \d+[eE][-+]\d+= 数字,后跟eor E,后跟运算符+ or -,后跟数字,以捕获类似的元素2e+3
  • \w+(?=\()-(A-Za-z0-9_)如果后面跟着(匹配函数,则匹配一个或多个单词字符,例如sin
  • \w+- 匹配一个或多个单词字符(A-Za-z0-9_)来匹配操作数,
  • [-+\/*%]- 匹配字符类中的一个字符,以匹配运算符
  • .- 匹配任何其他字符,匹配其他符号

替代项的顺序非常重要,因为最后一个替代项.将匹配任何字符,因此它必须是最后一个选项。\w+(?=\()与and类似的情况\w+,第二个将像前一个一样匹配所有内容,但是如果您不习惯区分函数和操作数,则\w+对于所有这些都足够了。

在更长的示例中,每个替代方案中的部分(?<name> ... )是一个命名的捕获组,您可以在演示中看到它如何将匹配的片段分组到组中,例如:操作数、运算符、函数等。