You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用ANTLR4解析时GetText()获取子查询丢失空格问题求助

解决ANTLR解析SQL时子查询空格丢失的问题

问题出在ANTLR默认的GetText()方法上——它只会返回语法分析所需的核心Token,自动忽略被归类到隐藏通道的Token(比如空格、换行符这类不影响语法结构的字符),所以提取子查询时会丢失空格。

下面给出两种可行的解决办法:

方法一:利用TokenStream截取原始完整文本

这种方法直接从输入的Token流中提取包含隐藏通道的完整文本,是最可靠的方案:

  1. 修改mockListener结构,添加CommonTokenStream成员用于获取Token信息:
type mockListener struct {
    *PlSqlBaseListener
    kv    map[string]interface{}
    stream *antlr.CommonTokenStream // 新增成员
}
  1. 创建Listener时传入TokenStream:
l := &mockListener{
    kv:    make(map[string]interface{}),
    stream: stream, // 传入之前创建的CommonTokenStream
}
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 15:22:38