在ANTLR中获取纯文本而非令牌的实现方法
获取ANTLR解析器中的纯文本内容
首先得提个小细节:你语法里的tag1Ops用了END_2_TAG,这大概率是笔误吧?应该对应END_1_TAG才对,不然标签开闭不匹配,解析肯定会出问题,先把这个小坑填上。
接下来回到你的核心需求:获取纯文本而非零散令牌。这里有两种实用方案,看你更倾向哪种:
方式一:优化语法,用词法规则捕获完整文本块
这种方式最高效,能让ANTLR直接把连续文本当成一个令牌,不用后续拼接。
调整后的语法如下:
grammar YourGrammar; code : codeBlock* EOF; codeBlock : text | tag1Ops | tag2Ops ; // 修正tag1Ops的结束标签,匹配对应的END_1_TAG tag1Ops: START_1_TAG ID END_1_TAG ; tag2Ops: START_2_TAG ID END_2_TAG ; // 解析器规则直接引用TEXT词法令牌 text: TEXT; // 注意:把HTML转义的<换成实际的<,ANTLR语法里直接写原始字符即可 START_1_TAG : '<%' ; END_1_TAG : '%>' ; START_2_TAG : '<<'; END_2_TAG : '>>' ; ID : [A-Za-z_][A-Za-z0-9_]*; INT_NUMBER: [0-9]+; // 隐藏无关空白(如果需要保留文本内的空格,可删掉这条规则) WS : ( ' ' | '\n' | '\r' | '\t')+ -> channel(HIDDEN); // 核心:定义TEXT词法规则,匹配所有非起始标签的内容 // 逻辑:要么是不含<的字符,要么是<后不跟%或<的内容(避免误匹配起始标签) TEXT: (~('<') | '<' (~('%' | '<')))+; // 删掉多余的ANY_CHAR和SPACES,TEXT已经覆盖这些场景,留着会干扰规则匹配
然后在代码中(以Java为例),用ANTLR的监听器或访问器提取文本:
监听器实现示例:
public class YourTextListener extends YourGrammarBaseListener { @Override public void enterText(YourGrammarParser.TextContext ctx) { // 直接获取TEXT令牌的完整文本 String plainText = ctx.TEXT().getText(); // 这里可以做自定义处理,比如打印、存储等 System.out.println("提取到纯文本:" + plainText); } }
访问器实现示例:
public class YourTextVisitor extends YourGrammarBaseVisitor<String> { @Override public String visitText(YourGrammarParser.TextContext ctx) { return ctx.TEXT().getText(); } }
方式二:不修改语法,拼接令牌文本(适合临时场景)
如果不想改动现有语法,也可以遍历text节点下的所有令牌,拼接出完整文本:
@Override public void enterText(YourGrammarParser.TextContext ctx) { StringBuilder textBuilder = new StringBuilder(); // 遍历text节点下的所有令牌并拼接 for (Token token : ctx.getTokens()) { textBuilder.append(token.getText()); } String plainText = textBuilder.toString(); // 执行后续处理 }
不过这种方式效率稍低,因为需要拼接多个零散令牌,更推荐第一种方案。
最后提醒:词法规则的顺序很关键!一定要把TEXT放在所有其他词法规则的后面,这样ANTLR会优先匹配标签、ID、数字等特定令牌,剩下的内容才会被TEXT捕获,避免标签被误识别为文本。
内容的提问来源于stack exchange,提问作者john




