使用go實(shí)現(xiàn)刪除sql里面的注釋和字符串功能(demo)
項(xiàng)目里面有一個(gè)需求,要對(duì)sql進(jìn)行簡(jiǎn)單的語(yǔ)法分析
為了避免sql里面的字符串和注釋對(duì)語(yǔ)法分析做干擾,我寫(xiě)了一個(gè)java函數(shù),對(duì)sql進(jìn)行修剪,刪除里面字符串和注釋,用空格代替
周末閑著沒(méi)事,我用go重新實(shí)現(xiàn)了這個(gè)功能,感覺(jué)應(yīng)該會(huì)有后來(lái)人可以用上
說(shuō)明:
sql里面的注釋有兩種單行注釋和多行注釋,其中單行注釋以--開(kāi)頭,以\n結(jié)尾,多行注釋以/開(kāi)頭,以/結(jié)尾
sql字符串是以'開(kāi)頭,'結(jié)尾,但特別的地方是連續(xù)兩個(gè)單引號(hào)是代表一個(gè)單引號(hào)而不是字符串結(jié)束標(biāo)志
關(guān)鍵函數(shù)如下:
`
/**
將字節(jié)數(shù)組里面注釋和字符串,用空格替換 rangeBeg和rangeEnd是數(shù)組元素起始位置 左閉右開(kāi)
*/
func TrimSqlByteArray(sql []byte, rangeBeg int, rangeEnd int) []byte {
sqlLength := rangeEnd - rangeBeg - 1;
//刪除注釋或者字符串后 用空格填充 必免因刪除導(dǎo)致粘連改變sql語(yǔ)義
const chPad = ' '
//結(jié)果切片,預(yù)分配空間為入?yún)ql長(zhǎng)度一半
result := make([] byte, 0, sqlLength / 2)
//本字符類型
var charType int = NORMAL;
for i := rangeBeg; i < rangeEnd; i++ {
/*
*utf8編碼不影響判斷
//跳過(guò)非英文字符
if sql[i] & 0x80 != 0 {
//utf8編碼:UTF-8是一種變長(zhǎng)字節(jié)編碼方式。對(duì)于某一個(gè)字符的UTF-8編碼,如果只有一個(gè)字節(jié)則其最高二進(jìn)制位為0;
//如果是多字節(jié),其第一個(gè)字節(jié)從最高位開(kāi)始,連續(xù)的二進(jìn)制位值為1的個(gè)數(shù)決定了其編碼的位數(shù),其余各字節(jié)均以10開(kāi)頭。
//UTF-8最多可用到6個(gè)字節(jié)。 這里不考慮異常,因?yàn)間o的字符串基本都是標(biāo)準(zhǔn)utf8編碼
i += getPreNotZeroCount(sql[i]) - 1
continue;
}
*/
//本字符類型 預(yù)設(shè)為普通字符
charType = NORMAL
ch := sql[i]
//下一個(gè)字符
var chNext byte;
chNext = getCharSafe(sql, rangeEnd, i + 1)
//非有效sql內(nèi)容結(jié)束位置
endPos := 0
if ch == '-' && chNext == '-' {
//單行注釋
charType = LINE
//下標(biāo)移到非有效字符的最后
endPos = seekToNext(sql, i + 2, rangeEnd, charType)
} else if ch == '/' && chNext == '*' {
//多行注釋
charType = MULTI
//下標(biāo)移到非有效字符的最后
endPos = seekToNext(sql, i + 2, rangeEnd, charType)
} else if ch == '\'' {
//字符串
charType = STRING
//下標(biāo)移到非有效字符的最后
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是數(shù)組邊界
*/
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字符串里面連續(xù)的單引號(hào)被認(rèn)為是' 則不是字符串結(jié)束標(biāo)志
if ch == '\'' && chNext == '\'' {
result = result + 1;
continue;
} else if ch == '\'' {
break;
}
}
break
default: break; } result++; return result; }
完整代碼及單元測(cè)試已上傳 https://github.com/kingstarer/kingstarer.git
到此這篇關(guān)于使用go實(shí)現(xiàn)刪除sql里面的注釋和字符串功能的文章就介紹到這了,更多相關(guān)go刪除sql注釋和字符串內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go語(yǔ)言利用Unmarshal解析json字符串的實(shí)現(xiàn)
本文主要介紹了Go語(yǔ)言利用Unmarshal解析json字符串的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
golang 40行代碼實(shí)現(xiàn)通用協(xié)程池
golang協(xié)程機(jī)制很方便的解決了并發(fā)編程的問(wèn)題,但是協(xié)程并不是沒(méi)有開(kāi)銷的,所以也需要適當(dāng)限制一下數(shù)量。這篇文章主要介紹了golang 40行代碼實(shí)現(xiàn)通用協(xié)程池,需要的朋友可以參考下2018-08-08
Golang使用Docker進(jìn)行集成測(cè)試的示例詳解
集成測(cè)試需要解決外部依賴問(wèn)題,如?MySQL、Redis、網(wǎng)絡(luò)等依賴,本文就來(lái)聊聊?Go?程序如何使用?Docker?來(lái)解決集成測(cè)試中外部依賴問(wèn)題吧2023-07-07
Go語(yǔ)言O(shè)RM框架構(gòu)造查詢條件示例詳解
這篇文章主要為大家介紹了Go語(yǔ)言O(shè)RM框架構(gòu)造查詢條件示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
Golang學(xué)習(xí)筆記(一):簡(jiǎn)介
這篇文章主要介紹了Golang學(xué)習(xí)筆記(一):簡(jiǎn)介,本文講解了Go語(yǔ)言最主要的特性、安裝、環(huán)境變量設(shè)置、整體目錄結(jié)構(gòu)、Helloworld、go命令、調(diào)試、編輯器設(shè)置等內(nèi)容,需要的朋友可以參考下2015-05-05
關(guān)于Go語(yǔ)言中特有的設(shè)計(jì)模式與實(shí)現(xiàn)方式講解
雖然Go語(yǔ)言沒(méi)有像其他語(yǔ)言那樣明確的設(shè)計(jì)模式,但在實(shí)踐中,開(kāi)發(fā)者們?nèi)匀话l(fā)現(xiàn)了一些在Go語(yǔ)言中特別適用的設(shè)計(jì)模式和實(shí)現(xiàn)方式,本文就來(lái)和大家一一進(jìn)行講解2023-05-05

