專案里面有一個需求,要對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; } } breakcase LINE:
for ; result < rangeEnd; result++ {
ch := sql[result]if ch == '\n' { break; } } breakcase 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; } } breakdefault:
break;
}result++;
return result;
}
`
完整代碼及單元測驗已上傳 https://github.com/kingstarer/kingstarer.git
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/228364.html
標籤:Go
下一篇:密碼學:一.異或加密
