正则表达式无法匹配开关案例模式

Regex can't match switch case pattern

W 我们需要解析一个规则,其中可能包含一个 switch case 指令。

由于我们考虑使用 Groovy 在 Java 代码中实现此解析器,因此我在 Groovy 中编写了以下代码:

1. class RuleParser {
2. String functionRegex = /(frml[0-9]*)((\s*@[a-zA-Z0-9_]*\s*)?(,\s*@[a-zA-Z0-9_]*\s*)*)/
3. String variableRegex = /@[a-zA-Z0-9_]*/
4. String numberRegex = /\s+[0-9]+/
5. String switchRegex = /switch(\s*1\s*)((\s*|\n)case)+((\s*|\n)default)?/
6. String caseRegex = /case\s*1\s*:\s*1/
7. String defaultRegex = /default\s*:\s*1/
8. String conditionRegex = /1(>=|<=|>|<|==|!=)1/

9. testRule(String rule){
10.       try {
11.          rule.eachMatch(numberRegex){ match->
12.             rule=rule.replaceAll(match, ' 1');
13.          }
14.          rule.eachMatch(functionRegex){ match->
15.             rule=rule.replaceAll(match, '1');
16.          }
17.          rule.eachMatch(variableRegex){ match->
18.             rule=rule.replaceAll(match, '1');
19.          }
20.          rule.eachMatch(defaultRegex){ match->
21.             rule=rule.replaceAll(match, 'default');
22.          }
23.          rule.eachMatch(caseRegex){ match->
24.             rule=rule.replaceAll(match, 'case');
25.          }
26.          rule.eachMatch(switchRegex){ match->
27.             rule=rule.replaceAll(match, '1');
28.          }
29.          Eval.me(rule)
30.          println "run successfully"
31.       } catch (Exception e) {
32.          e.printStackTrace()
33.       }
34.    }
35. }

首先我只是想根据我们的结构测试输入规则是否正确,例如我考虑了下面的规则示例来跟踪代码是否正常工作:

switch(@prm43) 
case 12: @msg13
case 14: @msg32
default: @msg100

它一直工作到第 26 行,当它到达第 26 行时,规则是:

switch(1) 
case
case
default

虽然完全按照switchRegex的模式,但是第28行之后没有任何变化,为什么?

很抱歉没有直接回答您的问题,但我似乎不太清楚您要达到的目标。您在进行一些替换后评估规则,但您的开关不合法 groovy(或 java 就此而言)。 switch 后面需要跟大括号。此外,我会尝试利用 groovy 的 DSL 功能,而不是制作解析器。如果解析器确实是您所需要的(缺少有关动机和上下文的信息),那么我建议使用像 jparsec 这样的组合器解析器:

https://github.com/jparsec/jparsec

用jparsec描述语法非常容易,而且非常易于维护。无论如何,为此使用正则表达式似乎是一个看起来像钉子的问题,因为我们只有一把锤子。

随着我对我的问题进行更多研究,我测试了一些其他解析器以评估解析我的语法的最佳方法。 首先,按照 loteq 的建议,我在我的项目中检查了 jparsec。但不幸的是,我找不到足够的信息和使用该解析器的良好参考。 所以,我寻找另一个解析器来完成我的特定语法工作,我找到了 antlr4。然后,我开发我的语法并将其保存在 RuleExpr.g4 文件中,以通过 antlr 生成词法分析器和解析器文件。语法如下所示:

grammar RuleExp;

start
    :   statement+
    ;

statement
    :   assignment
    |   message
    |   ifElseExp
    |   switchExp
    ;

ifElseExp
    :   'if' '(' relCnd ')' 'then' '{' start '}'
    |   'if' '(' relCnd ')' 'then' '{' start '}' elseExp
    ;

elseExp
    :   'else' ifElseExp
    |   'else' '{' start '}'
    ;

switchExp
    :   'switch' '(' relCnd ')' caseExp
    ;

caseExp
    :   'case' terminal ':' '{' start '}' caseExp
    |   dfltExpr
    ;

dfltExpr
    :   'default' ':' '{' start '}'
    ;

message
    :   '@msg'Digit+
    ;

assignment
    :   id '=' addStmt
    ;

relCnd
    :   relCnd  '>' logCnd
    |   relCnd  '<' logCnd
    |   relCnd  '>=' logCnd
    |   relCnd  '<=' logCnd
    |   relCnd  '==' logCnd
    |   relCnd  '!=' logCnd 
    |   logCnd
    ;

logCnd
    :   logCnd  'AND'   termCnd
    |   logCnd  'OR'    termCnd
    |   logCnd  'XOR'   termCnd
    |   'NOT'   termCnd
    |   termCnd
    ;

addStmt
    :   addStmt '+' mulStmt
    |   addStmt '-' mulStmt
    |   mulStmt
    ;


mulStmt
    :   mulStmt '*' terminal
    |   mulStmt '/' terminal
    |   mulStmt '^' terminal
    |   terminal
    ;

terminal
    :   '('addStmt')'
    |   id
    |   number
    ;

termCnd
    :   '('relCnd')'
    |   id
    |   number
    ;

id
    :   '@prmt'(Digit)+
    |   '@fild'(Digit)+
    |   '@infF'(Digit)+
    |   '@mthd'(Digit)+
    |   '@cmpnt'(Digit)+
    |   '@oprt'(Digit)+
    |   Letter(Letter|Digit)*
    ;

number
    :   Digit+ ('.' Digit+)?
    ;

Letter
    :   'a'..'z'
    |   'A'..'Z'
    |   '_'
    ;

Digit
    :   '0'..'9'
    ;

WS  :   [ \t\r\n]+  ->  skip 
    ;

之后我使用 antlr 生成的词法分析器和解析器解析我的示例代码

public void checkSyntax(String rule) {
      // TODO Auto-generated method stub
      try {
         CharStream stream=new ANTLRInputStream(decodeRule(rule));
         RuleExpLexer lexer=new RuleExpLexer(stream);
         CommonTokenStream tokens=new CommonTokenStream(lexer);
         RuleExpParser parser=new RuleExpParser(tokens);
         parser.start();
      } catch (Exception e) {
         // TODO: handle exception
         throw new ApplicationExceptions("uacRule is Wrong");
      }
   }