正则表达式不能匹配开关案例模式

时间:2015-05-13 09:24:45

标签: java regex parsing groovy

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行之后没有任何变化,为什么?

2 个答案:

答案 0 :(得分:2)

我很抱歉没有为你的问题提出一个直截了当的答案,但我似乎有点不清楚你想要达到的目标。您在进行一些替换后评估规则,但是您的切换不合法groovy(或java)。开关需要跟随花括号。此外,我会尝试利用groovy的DSL功能而不是制作解析器。如果解析器确实是你需要的(缺少关于动机和上下文的信息),那么我建议使用像jparsec这样的组合解析器:

https://github.com/jparsec/jparsec

使用jparsec描述语法非常容易,并且它非常易于维护。在任何情况下,使用正则表达式似乎是一个看起来像钉子的问题,因为我们只有一把锤子。

答案 1 :(得分:0)

当我更多地研究我的问题时,我会测试一些其他解析器来评估解析语法的最佳方法。 首先,正如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");
      }
   }