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 关注
- 147 浏览
添加回答
举报