经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Go语言 » 查看文章
我的go练手项目--使用go实现“删除sql里面的注释和字符串”功能
来源:cnblogs  作者:皇家救星  时间:2020/12/8 9:09:38  对本文有异议

项目里面有一个需求,要对sql进行简单的语法分析

为了避免sql里面的字符串和注释对语法分析做干扰,我写了一个java函数,对sql进行修剪,删除里面字符串和注释,用空格代替
周末闲着没事,我用go重新实现了这个功能,感觉应该会有后来人可以用上

说明:
sql里面的注释有两种单行注释和多行注释,其中单行注释以--开头,以\n结尾,多行注释以/开头,以/结尾
sql字符串是以'开头,'结尾,但特别的地方是连续两个单引号是代表一个单引号而不是字符串结束标志

关键函数如下:

`
/**

  • 将字节数组里面注释和字符串,用空格替换 rangeBeg和rangeEnd是数组元素起始位置 左闭右开
    */
    func TrimSqlByteArray(sql []byte, rangeBeg int, rangeEnd int) []byte {
    sqlLength := rangeEnd - rangeBeg - 1;
    //删除注释或者字符串后 用空格填充 必免因删除导致粘连改变sql语义
    const chPad = ' '

    //结果切片,预分配空间为入参sql长度一半
    result := make([] byte, 0, sqlLength / 2)

    //本字符类型
    var charType int = NORMAL;
    for i := rangeBeg; i < rangeEnd; i++ {
    /*
    *utf8编码不影响判断
    //跳过非英文字符
    if sql[i] & 0x80 != 0 {
    //utf8编码:UTF-8是一种变长字节编码方式。对于某一个字符的UTF-8编码,如果只有一个字节则其最高二进制位为0;
    //如果是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了其编码的位数,其余各字节均以10开头。
    //UTF-8最多可用到6个字节。 这里不考虑异常,因为go的字符串基本都是标准utf8编码
    i += getPreNotZeroCount(sql[i]) - 1
    continue;
    }
    */

    1. //本字符类型 预设为普通字符
    2. charType = NORMAL
    3. ch := sql[i]
    4. //下一个字符
    5. var chNext byte;
    6. chNext = getCharSafe(sql, rangeEnd, i + 1)
    7. //非有效sql内容结束位置
    8. endPos := 0
    9. if ch == '-' && chNext == '-' {
    10. //单行注释
    11. charType = LINE
    12. //下标移到非有效字符的最后
    13. endPos = seekToNext(sql, i + 2, rangeEnd, charType)
    14. } else if ch == '/' && chNext == '*' {
    15. //多行注释
    16. charType = MULTI
    17. //下标移到非有效字符的最后
    18. endPos = seekToNext(sql, i + 2, rangeEnd, charType)
    19. } else if ch == '\'' {
    20. //字符串
    21. charType = STRING
    22. //下标移到非有效字符的最后
    23. endPos = seekToNext(sql, i + 1, rangeEnd, charType)
    24. }
    25. //如果字符是非有效字符 则用空格代替 否则保持原样
    26. if charType == NORMAL {
    27. result = append(result, ch)
    28. } else {
    29. result = append(result, chPad)
    30. i = endPos - 1
    31. }

    }

    return result;
    }

/**

  • 获取字符串或者注释的右边界位置(不包含)

  • rangeEnd是数组边界
    */
    func seekToNext(sql []byte, begPos int, rangeEnd int, charType int) int {

    result := begPos;

    switch charType {
    case MULTI:
    for ; result < rangeEnd; result++ {
    ch := sql[result]
    chNext := getCharSafe(sql, rangeEnd, result+ 1)

    1. if ch == '*' && chNext == '/' {
    2. result = result + 1;
    3. break;
    4. }
    5. }
    6. break

    case LINE:
    for ; result < rangeEnd; result++ {
    ch := sql[result]

    1. if ch == '\n' {
    2. break;
    3. }
    4. }
    5. break

    case STRING:
    for ; result < rangeEnd; result++ {
    ch := sql[result]
    chNext := getCharSafe(sql, rangeEnd, result + 1)

    1. //sql字符串里面连续的单引号被认为是' 则不是字符串结束标志
    2. if ch == '\'' && chNext == '\'' {
    3. result = result + 1;
    4. continue;
    5. } else if ch == '\'' {
    6. break;
    7. }
    8. }
    9. break

    default:
    break;
    }

    result++;

    return result;
    }
    `

完整代码及单元测试已上传 https://github.com/kingstarer/kingstarer.git

原文链接:http://www.cnblogs.com/kingstarer/p/14058474.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号