正则表达式无法匹配开关案例模式
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");
}
}
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");
}
}