使用ANTLR4解析时GetText()获取子查询丢失空格问题求助
解决ANTLR解析SQL时子查询空格丢失的问题
问题出在ANTLR默认的GetText()方法上——它只会返回语法分析所需的核心Token,自动忽略被归类到隐藏通道的Token(比如空格、换行符这类不影响语法结构的字符),所以提取子查询时会丢失空格。
下面给出两种可行的解决办法:
方法一:利用TokenStream截取原始完整文本
这种方法直接从输入的Token流中提取包含隐藏通道的完整文本,是最可靠的方案:
- 修改
mockListener结构,添加CommonTokenStream成员用于获取Token信息:
type mockListener struct { *PlSqlBaseListener kv map[string]interface{} stream *antlr.CommonTokenStream // 新增成员 }
- 创建Listener时传入TokenStream:
l := &mockListener{ kv: make(map[string]interface{}), stream: stream, // 传入之前创建的CommonTokenStream }
- 在
EnterInsert_statement方法中,替换原来的valStr := ValList[i].GetText(),改为从Token流中截取完整文本:
func (s *mockListener) EnterInsert_statement(ctx *Insert_statementContext) { singTblInsert := ctx.Single_table_insert() insertInto := singTblInsert.Insert_into_clause() colList := insertInto.Paren_column_list().Column_list() ValList := singTblInsert.Values_clause().Expressions().AllExpression() colNames := colList.AllColumn_name() for i, col := range colNames { colName := col.GetText() // 获取当前表达式的起始和结束Token索引 startIdx := ValList[i].GetStart().GetTokenIndex() stopIdx := ValList[i].GetStop().GetTokenIndex() // 获取包含隐藏通道(空格等)的所有Token tokens := s.stream.GetTokens(startIdx, stopIdx, antlr.TokenDefaultChannel|antlr.TokenHiddenChannel) // 拼接Token文本 var valStr strings.Builder for _, token := range tokens { valStr.WriteString(token.GetText()) } s.kv[colName] = valStr.String() } }
这种方式直接复用原始SQL中的空格,完全避免手动处理语法节点的麻烦。
方法二:遍历语法树节点手动拼接文本(不推荐)
如果无法传递TokenStream,可以递归遍历子查询的语法树节点,在合适的位置手动添加空格。但这种方法需要覆盖所有语法场景,容易遗漏或出错,示例如下(仅针对子查询场景):
func getFullText(ctx antlr.ParseTree) string { var text strings.Builder for i := 0; i < ctx.GetChildCount(); i++ { child := ctx.GetChild(i) if i > 0 { // 根据节点类型判断是否需要添加空格 if _, ok := child.(*Select_statementContext); ok { text.WriteString(" ") } // 其他节点类型的空格判断需要逐个添加,非常繁琐 } text.WriteString(getFullText(child)) } if leaf, ok := ctx.(antlr.TerminalNode); ok { text.WriteString(leaf.GetText()) } return text.String() }
调用时用valStr := getFullText(ValList[i])替代原来的GetText(),但这种方法维护成本极高,不建议使用。
内容的提问来源于stack exchange,提问作者IsaIkari
相关产品推荐
相关产品推荐

