java - ANTLR 嵌套函数

标签 java antlr4 antlr3

ANTLR 适合这个项目吗?

我正在寻找处理和转换用户输入的字符串,其中可能包含自定义函数。例如,用户可能会在字符串中写入类似 $CAPITALIZE('word') 的内容,而我想执行 使用 StringUtils 在后台进行实际转换。

我想用户有时会编写如下嵌套函数:

$RIGHT_PAD($RIGHT($CAPITALIZE('a123456789'),6),3,'0')

预期输出将是“A12345000”的字符串值。

我尝试使用正则表达式将函数分开,但一旦嵌套,就没那么容易了。我想我可能会尝试编写自己的解析器,并且在进行研究时我发现了一篇建议改用 ANTLR 的文章。

这是 ANTLR 适合的东西吗?如果是这样,是否有任何类似的例子可供我查看?或者有人会给我一个例子,说明我如何在 ANTLR 中写出这个,这样我就可以拥有可以单独处理和以嵌套方式处理的自定义函数。

函数:

  • $CAPITALIZE(字符串字符串)
  • $INDEX_OF(字符串序列,字符串搜索序列)
  • $LEFT(字符串 str, int len)
  • $LEFT_PAD(String str, int size,char padChar)
  • $LOWERCASE(字符串字符串)
  • $RIGHT(String str, int len)
  • $RIGHT_PAD(String str, int size, char padChar)
  • $STRIP(字符串字符串)
  • $STRIP_ACCENTS(字符串输入)
  • $SUBSTRING(String str, int start)
  • $SUBSTRING(String str, int start, int end)
  • $TRIM(字符串字符串)
  • $TRUNCATE(String str, int maxWidth)
  • $UPPERCASE(字符串字符串)

基本示例:

  • $CAPITALIZE('单词') → '单词'
  • $INDEX_OF('word', 'r') → 2
  • $LEFT('0123456789',6) → '012345'
  • $LEFT_PAD('0123456789',3, '0') → '0000123456789'
  • $LOWERCASE('WoRd') → '单词'
  • $RIGHT('0123456789',6) → '456789'
  • $RIGHT_PAD('0123456789',3, '0') → '0123456789000'
  • $STRIP('单词') → '单词'
  • $STRIP_ACCENTS('word') → 'word'
  • $SUBSTRING('word', 1) → 'ord'
  • $SUBSTRING('word', 0, 2) → 'wor'
  • $TRIM('单词') → '单词'
  • $TRUNCATE('更多单词', 3) → '更多'
  • $UPPERCASE('单词') → '单词'

嵌套示例

  • $LEFT_PAD($LEFT('123456789',6),3,'0') → '000123456'
  • $RIGHT_PAD($RIGHT($CAPITALIZE('a123456789'),6),3,'0') → 'A12345000'

实例: 我所说的实际示例的意思是,这就是我期望的字符串值的样子。你会注意到有些变量写成 ${var}。在将字符串传递给 ANTLR 之前,这些变量将使用 Apache Commons StringSubstitutor 替换为实际字符串值(如果结果证明我应该使用它)

用户写入的初始字符串 \HomeDir\Students\$RIGHT(${graduation.year},2)\$LEFT_PAD($LEFT(${state.id},6),3,'0')

StringSubstitutor处理后的字符串 \HomeDir\Students\$RIGHT('2020',2)\$LEFT_PAD($LEFT('123456789',6),3,'0')

字符串被 ANTLR 处理后 (以及我的最终输出)

\HomeDir\Students\20\000123456

ANTLR 是我应该用于这个项目的东西,还是其他更适合的东西?

最佳答案

是的,ANTLR 将是一个不错的选择。请记住,ANTLR 只为您进行解析,并为您提供一种遍历生成的解析树的机制。您将必须编写代码来评估表达式。

在您的情况下,当词法分析器偶然发现 '$' 时,需要触发词法分析器,方法是将词法状态推送为“函数模式”。当它看到 ')' 时,应该从词法堆栈中弹出一个这样的“in-a-function-mode”。

在 ANTLR wiki 上阅读所有关于词法模式/堆栈的内容:https://github.com/antlr/antlr4/blob/master/doc/lexer-rules.md

这是一个快速演示,说明它如何适用于 ANTLR4(ANTLR3 不支持词法模式):

文件:TLexer.g4

lexer grammar TLexer;

TEXT
 : ~[$]
 ;

FUNCTION_START
 : '$' -> pushMode(IN_FUNCTION), skip
 ;

mode IN_FUNCTION;
  FUNTION_NESTED : '$' -> pushMode(IN_FUNCTION), skip;
  ID             : [a-zA-Z_]+;
  PAR_OPEN       : '(';
  PAR_CLOSE      : ')' -> popMode;
  NUMBER         : [0-9]+;
  STRING         : '\'' ( ~'\'' | '\'\'' )* '\'';
  COMMA          : ',';
  SPACE          : [ \t\r\n]-> skip;

文件:TParser.g4

parser grammar TParser;

options {
  tokenVocab=TLexer;
}

parse
 : atom* EOF
 ;

atom
 : text
 | function
 ;

text
 : TEXT+
 ;

function
 : ID params
 ;

params
 : PAR_OPEN ( param ( COMMA param )* )? PAR_CLOSE
 ;

param
 : NUMBER
 | STRING
 | function
 ;

使用 IntelliJ 的 ANTLR4 插件,您可以轻松地从解析器测试 parse 方法并为其提供以下输入:foo $RIGHT_PAD($RIGHT($CAPITALIZE('a123456789' ), 6), 3, '0') bar,会生成如下图的解析树:

enter image description here

关于java - ANTLR 嵌套函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51955458/

相关文章:

antlr - 如何匹配字符串,但不区分大小写?

c - 在 C 目标中用 antlr3 解析一些特定的语句

c++ - Antlr4 C++ 访客 API

java - 在不和谐机器人上上传用户文件

java - Android SDK 中缺少 android.net.SntpClient

java - 在 Hadoop 分布式缓存中创建和放置文件

pretty-print - 如何在一般遍历解析树时访问 ANTLR4 中的备用标签?

java - 我如何引用在 ANTLR 中多次调用同一规则?

antlr 匹配输入使用多个替代错误

java - Android 中的多分辨率?