1. 程式人生 > 實用技巧 >我的go練手專案--使用go實現“刪除sql裡面的註釋和字串”功能

我的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