6

毫无疑问,SO可以解决我的特定问题。我对正则表达式知之甚少。为此,我正在使用 Regex 类在 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);
}

输出:

2
!
+
atan2
(
3
+
9
,
2
+
3
)
-
2
*
PI
+
3
/
3
-
9
-
12
%
3
*
sin
(
9
-
9
)
+
(
2
+
6
/
2
)

问题是现在表达式可以包含用户定义格式的矩阵。在函数的情况下,我想将每个矩阵视为操作数或参数。

输入 1:

String input_1 = "2+3-9*[{2+3,2,6},{7,2+3,2+3i}]+9*6"

输出应该是:

2
+
3
-
9
*
[{2+3,2,6},{7,2+3,2+3i}]
+
9
*
6

输入 2:

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

输出应该是:

{[2,5][9/8,func(2+3)]}
+
9
*
8
/
5

输入 3:

String input_3 = "<[2,9,2.36][2,3,2!]>*<[2,3,9][23+9*8/8,2,3]>"

输出应该是:

<[2,9,2.36][2,3,2!]>
*
<[2,3,9][23+9*8/8,2,3]>

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

4

2 回答 2

3

我认为您可以尝试以下方法:

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

演示

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

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


\[[^\]]+\]|<[^>]+>|\{[^\}]+\}匹配左括号 ( ,{[) <、非括号字符和右括号 ( }, ], >),因此如果没有嵌套的同类型括号,则没有问题。用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");
        }
    }
}

替代方案的解释:

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

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

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

于 2015-10-12T12:40:20.773 回答
2

使用正则表达式,您无法匹配任何级别的嵌套平衡括号。

例如,在您的第二个示例中,{[2,5][9/8,func(2+3)]}您需要将左大括号与右大括号匹配,但您需要跟踪有多少个打开和关闭内大括号/括号/等。这不能用正则表达式来完成。

另一方面,如果您简化问题以消除任何平衡要求,那么您可能可以使用正则表达式来处理。

于 2015-10-11T21:12:20.307 回答