使用函数替换正则表达式子匹配

时间:2013-06-12 12:25:05

标签: regex go

假设我有像

这样的字符串
input := `bla bla b:foo="hop" blablabla b:bar="hu?"`

我希望使用函数替换b:foo="hop"b:bar="hu?"中引号之间的部分。

构建正则表达式以获得匹配和子匹配很容易,例如

r := regexp.MustCompile(`\bb:\w+="([^"]+)"`)

然后调用ReplaceAllStringFunc但问题是回调收到整个匹配而不是子匹配:

fmt.Println(r.ReplaceAllStringFunc(input, func(m string) string {
    // m is the whole match here. Damn.
}))

如何更换子匹配?

现在,我还没有找到一个更好的解决方案,而不是使用正则表达式在回调中分解自己m,并在处理完子匹配后重建字符串。

如果可以在Go中使用,我会使用另一种方法,看看是否有正面看法,但事实并非如此(无论如何它们都不是必需的)。

我可以在这做什么?


编辑:这是我想要简化的当前解决方案:

func complexFunc(s string) string {
   return "dbvalue("+s+")" // this could be more complex
}
func main() {
        input := `bla bla b:foo="hop" blablabla b:bar="hu?"`
        r := regexp.MustCompile(`(\bb:\w+=")([^"]+)`)
        fmt.Println(r.ReplaceAllStringFunc(input, func(m string) string {
                parts := r.FindStringSubmatch(m)
                return parts[1] + complexFunc(parts[2])
        }))
}

(playground link)

困扰我的是我必须两次应用正则表达式。这听起来不对。

2 个答案:

答案 0 :(得分:2)

我不喜欢下面的代码,但它似乎做了你似乎想做的事情:

package main

import (
        "fmt"
        "regexp"
)

func main() {
        input := `bla bla b:foo="hop" blablabla b:bar="hu?"`
        r := regexp.MustCompile(`\bb:\w+="([^"]+)"`)
        r2 := regexp.MustCompile(`"([^"]+)"`)
        fmt.Println(r.ReplaceAllStringFunc(input, func(m string) string {
                return r2.ReplaceAllString(m, `"${2}whatever"`)
        }))
}

Playground


输出

bla bla b:foo="whatever" blablabla b:bar="whatever"

编辑:拿II。


package main

import (
        "fmt"
        "regexp"
)

func computedFrom(s string) string {
        return fmt.Sprintf("computedFrom(%s)", s)
}

func main() {
        input := `bla bla b:foo="hop" blablabla b:bar="hu?"`
        r := regexp.MustCompile(`\bb:\w+="([^"]+)"`)
        r2 := regexp.MustCompile(`"([^"]+)"`)
        fmt.Println(r.ReplaceAllStringFunc(input, func(m string) string {
                match := string(r2.Find([]byte(m)))
                return r2.ReplaceAllString(m, computedFrom(match))
        }))
}

Playground


输出:

bla bla b:foo=computedFrom("hop") blablabla b:bar=computedFrom("hu?")

答案 1 :(得分:0)

看起来 OP 为此创建了一个问题,但截至本文,仍未实现 https://github.com/golang/go/issues/5690

幸运的是,网络上的其他人似乎提供了自己的函数来执行此操作https://gist.github.com/elliotchance/d419395aa776d632d897

func ReplaceAllStringSubmatchFunc(re *regexp.Regexp, str string, repl func([]string) string) string {
    result := ""
    lastIndex := 0

    for _, v := range re.FindAllSubmatchIndex([]byte(str), -1) {
        groups := []string{}
        for i := 0; i < len(v); i += 2 {
            groups = append(groups, str[v[i]:v[i+1]])
        }

        result += str[lastIndex:v[0]] + repl(groups)
        lastIndex = v[1]
    }

    return result + str[lastIndex:]
}