我的go練手項目--使用go實現“刪除sql裏面的註釋和字符串”功能

項目裏面有一個需求,要對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;
    }
    */

      //本字符類型 預設爲普通字符
      charType = NORMAL
      ch := sql[i]
    
      //下一個字符
      var chNext byte;
      chNext = getCharSafe(sql, rangeEnd, i + 1)
    
      //非有效sql內容結束位置
      endPos := 0
    
      if ch == '-' && chNext == '-' {
      	//單行註釋
      	charType = LINE
      	//下標移到非有效字符的最後
      	endPos = seekToNext(sql, i + 2, rangeEnd, charType)
      } else if ch == '/' && chNext == '*' {
      	//多行註釋
      	charType = MULTI
      	//下標移到非有效字符的最後
      	endPos = seekToNext(sql, i + 2, rangeEnd, charType)
      } else if ch == '\'' {
      	//字符串
      	charType = STRING
      	//下標移到非有效字符的最後
      	endPos = seekToNext(sql, i + 1, rangeEnd, charType)
      }
    
      //如果字符是非有效字符 則用空格代替 否則保持原樣
      if charType == NORMAL {
      	result = append(result, ch)
      } else {
      	result = append(result, chPad)
      	i = endPos - 1
      }
    

    }

    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)

      	if ch == '*' && chNext == '/' {
      		result = result + 1;
      		break;
      	}
      }
    
      break
    

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

      	if ch == '\n' {
      		break;
      	}
      }
    
      break
    

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

      	//sql字符串裏面連續的單引號被認爲是' 則不是字符串結束標誌
      	if ch == '\'' && chNext == '\'' {
      		result = result + 1;
      		continue;
      	} else if ch == '\'' {
      		break;
      	}
      }
    
      break
    

    default:
    break;
    }

    result++;

    return result;
    }
    `

完整代碼及單元測試已上傳 https://github.com/kingstarer/kingstarer.git

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章