2 回答

TA貢獻1785條經驗 獲得超4個贊
您的正則表達式似乎有兩個主要問題,其中一個比另一個更容易處理:
正則表達式天生就不擅長處理遞歸匹配,例如分組左括號和右括號,因為它們沒有內存。就您而言,我認為您已嘗試通過將自己限制在一些特定情況下來解決此問題,但正則表達式的貪婪性質在這里對您不利。
您不匹配右括號前可能有空格的情況。
這兩個問題一起導致您的正則表達式在這兩種情況下失敗,但也導致您的第一個案例匹配。
要解決此問題,您必須在將字符串發送到正則表達式之前對字符串進行一些預處理:
if strings.HasPrefix(rawSql, "(") { rawSql = rawSql[1:len(rawSql) - 1] }
這將去掉任何外括號,如果沒有內存或額外的子句,正則表達式將無法忽略這些括號。
接下來,您需要修改正則表達式以處理內部函數調用和$__timeFilter
調用之間可能存在空格的情況:
func getRegex(name string) string { return fmt.Sprintf("\\$__%s\\b(\\((.*?\\)?)\\s*\\))?", name) }
這樣做之后,您的正則表達式應該可以工作了。您可以在此 playground 鏈接上找到完整示例。

TA貢獻1797條經驗 獲得超6個贊
盡管我最終不得不走另一條路,但我還是選擇了 Woody 的答案作為正確答案。附加的測試用例不包括某些場景,結果我還必須能夠提取括號內的參數。所以這是我的最終解決方案,我手動解析文本,找到邊界括號并提取它們之間的任何內容:
// getMacroMatches extracts macro strings with their respective arguments from the sql input given
// It manually parses the string to find the closing parenthesis of the macro (because regex has no memory)
func getMacroMatches(input string, name string) ([][]string, error) {
macroName := fmt.Sprintf("\\$__%s\\b", name)
matchedMacros := [][]string{}
rgx, err := regexp.Compile(macroName)
if err != nil {
return nil, err
}
// get all matching macro instances
matched := rgx.FindAllStringIndex(input, -1)
if matched == nil {
return nil, nil
}
for matchedIndex := 0; matchedIndex < len(matched); matchedIndex++ {
var macroEnd = 0
var argStart = 0
macroStart := matched[matchedIndex][0]
inputCopy := input[macroStart:]
cache := make([]rune, 0)
// find the opening and closing arguments brackets
for idx, r := range inputCopy {
if len(cache) == 0 && macroEnd > 0 {
break
}
switch r {
case '(':
cache = append(cache, r)
if argStart == 0 {
argStart = idx + 1
}
case ')':
l := len(cache)
if l == 0 {
break
}
cache = cache[:l-1]
macroEnd = idx + 1
default:
continue
}
}
// macroEnd equals to 0 means there are no parentheses, so just set it
// to the end of the regex match
if macroEnd == 0 {
macroEnd = matched[matchedIndex][1] - macroStart
}
macroString := inputCopy[0:macroEnd]
macroMatch := []string{macroString}
args := ""
// if opening parenthesis was found, extract contents as arguments
if argStart > 0 {
args = inputCopy[argStart : macroEnd-1]
}
macroMatch = append(macroMatch, args)
matchedMacros = append(matchedMacros, macroMatch)
}
return matchedMacros, nil
}
游樂場鏈接:https://go.dev/play/p/-odWKMBLCBv
- 2 回答
- 0 關注
- 201 瀏覽
添加回答
舉報