16

假设我有类似的字符串

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])
        }))
}

(游乐场链接)

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

4

2 回答 2

3

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

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"`)
        }))
}

操场


输出

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

编辑:拿二。


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))
        }))
}

操场


输出:

bla bla b:foo=computedFrom("hop") blablabla b:bar=computedFrom("hu?")
于 2013-06-12T12:49:32.347 回答
1

看起来 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:]
}
于 2021-01-25T21:15:19.453 回答