假设我有像
这样的字符串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])
}))
}
困扰我的是我必须两次应用正则表达式。这听起来不对。
答案 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"`)
}))
}
输出
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))
}))
}
输出:
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:]
}