如何从 regexp.ReplaceAllFunc 访问捕获组?
How to access a capturing group from regexp.ReplaceAllFunc?
如何从 ReplaceAllFunc() 内部访问捕获组?
package main
import (
"fmt"
"regexp"
)
func main() {
body := []byte("Visit this page: [PageName]")
search := regexp.MustCompile("\[([a-zA-Z]+)\]")
body = search.ReplaceAllFunc(body, func(s []byte) []byte {
// How can I access the capture group here?
})
fmt.Println(string(body))
}
目标是将 [PageName]
替换为 <a href="/view/PageName">PageName</a>
。
这是 Writing Web Applications Go 教程底部 "Other tasks" 部分下的最后一个任务。
我同意在函数内部访问捕获组是最理想的,我认为 regexp.ReplaceAllFunc
不可能。
关于如何使用该功能执行此操作,我现在唯一想到的是:
package main
import (
"fmt"
"regexp"
)
func main() {
body := []byte("Visit this page: [PageName] [OtherPageName]")
search := regexp.MustCompile("\[[a-zA-Z]+\]")
body = search.ReplaceAllFunc(body, func(s []byte) []byte {
m := string(s[1 : len(s)-1])
return []byte("<a href=\"/view/" + m + "\">" + m + "</a>")
})
fmt.Println(string(body))
}
编辑
还有另一种方法我知道如何做你想做的事。您需要知道的第一件事是您可以使用语法 (?:re)
指定非捕获组,其中 re
是您的正则表达式。这不是必需的,但会减少不感兴趣的匹配项的数量。
接下来要知道的是 regexp.FindAllSubmatcheIndex。它将 return 个切片的切片,其中每个内部切片代表 所有 个子匹配的范围,用于给定的正则表达式匹配。
有了这两件事,您就可以构建一些通用的解决方案:
package main
import (
"fmt"
"regexp"
)
func ReplaceAllSubmatchFunc(re *regexp.Regexp, b []byte, f func(s []byte) []byte) []byte {
idxs := re.FindAllSubmatchIndex(b, -1)
if len(idxs) == 0 {
return b
}
l := len(idxs)
ret := append([]byte{}, b[:idxs[0][0]]...)
for i, pair := range idxs {
// replace internal submatch with result of user supplied function
ret = append(ret, f(b[pair[2]:pair[3]])...)
if i+1 < l {
ret = append(ret, b[pair[1]:idxs[i+1][0]]...)
}
}
ret = append(ret, b[idxs[len(idxs)-1][1]:]...)
return ret
}
func main() {
body := []byte("Visit this page: [PageName] [OtherPageName][XYZ] [XY]")
search := regexp.MustCompile("(?:\[)([a-zA-Z]+)(?:\])")
body = ReplaceAllSubmatchFunc(search, body, func(s []byte) []byte {
m := string(s)
return []byte("<a href=\"/view/" + m + "\">" + m + "</a>")
})
fmt.Println(string(body))
}
您必须先调用 ReplaceAllFunc
,然后在同一正则表达式的函数调用 FindStringSubmatch
中再次调用。喜欢:
func (p parser) substituteEnvVars(data []byte) ([]byte, error) {
var err error
substituted := p.envVarPattern.ReplaceAllFunc(data, func(matched []byte) []byte {
varName := p.envVarPattern.FindStringSubmatch(string(matched))[1]
value := os.Getenv(varName)
if len(value) == 0 {
log.Printf("Fatal error substituting environment variable %s\n", varName)
}
return []byte(value)
});
return substituted, err
}
如果你想在ReplaceAllFunc
中获取组,你可以使用ReplaceAllString
获取子组。
package main
import (
"fmt"
"regexp"
)
func main() {
body := []byte("Visit this page: [PageName]")
search := regexp.MustCompile("\[([a-zA-Z]+)\]")
body = search.ReplaceAllFunc(body, func(s []byte) []byte {
// How can I access the capture group here?
group := search.ReplaceAllString(string(s), ``)
fmt.Println(group)
// handle group as you wish
newGroup := "<a href='/view/" + group + "'>" + group + "</a>"
return []byte(newGroup)
})
fmt.Println(string(body))
}
当有很多组时,你可以通过这种方式得到每个组,然后处理每个组和return想要的值。
如何从 ReplaceAllFunc() 内部访问捕获组?
package main
import (
"fmt"
"regexp"
)
func main() {
body := []byte("Visit this page: [PageName]")
search := regexp.MustCompile("\[([a-zA-Z]+)\]")
body = search.ReplaceAllFunc(body, func(s []byte) []byte {
// How can I access the capture group here?
})
fmt.Println(string(body))
}
目标是将 [PageName]
替换为 <a href="/view/PageName">PageName</a>
。
这是 Writing Web Applications Go 教程底部 "Other tasks" 部分下的最后一个任务。
我同意在函数内部访问捕获组是最理想的,我认为 regexp.ReplaceAllFunc
不可能。
关于如何使用该功能执行此操作,我现在唯一想到的是:
package main
import (
"fmt"
"regexp"
)
func main() {
body := []byte("Visit this page: [PageName] [OtherPageName]")
search := regexp.MustCompile("\[[a-zA-Z]+\]")
body = search.ReplaceAllFunc(body, func(s []byte) []byte {
m := string(s[1 : len(s)-1])
return []byte("<a href=\"/view/" + m + "\">" + m + "</a>")
})
fmt.Println(string(body))
}
编辑
还有另一种方法我知道如何做你想做的事。您需要知道的第一件事是您可以使用语法 (?:re)
指定非捕获组,其中 re
是您的正则表达式。这不是必需的,但会减少不感兴趣的匹配项的数量。
接下来要知道的是 regexp.FindAllSubmatcheIndex。它将 return 个切片的切片,其中每个内部切片代表 所有 个子匹配的范围,用于给定的正则表达式匹配。
有了这两件事,您就可以构建一些通用的解决方案:
package main
import (
"fmt"
"regexp"
)
func ReplaceAllSubmatchFunc(re *regexp.Regexp, b []byte, f func(s []byte) []byte) []byte {
idxs := re.FindAllSubmatchIndex(b, -1)
if len(idxs) == 0 {
return b
}
l := len(idxs)
ret := append([]byte{}, b[:idxs[0][0]]...)
for i, pair := range idxs {
// replace internal submatch with result of user supplied function
ret = append(ret, f(b[pair[2]:pair[3]])...)
if i+1 < l {
ret = append(ret, b[pair[1]:idxs[i+1][0]]...)
}
}
ret = append(ret, b[idxs[len(idxs)-1][1]:]...)
return ret
}
func main() {
body := []byte("Visit this page: [PageName] [OtherPageName][XYZ] [XY]")
search := regexp.MustCompile("(?:\[)([a-zA-Z]+)(?:\])")
body = ReplaceAllSubmatchFunc(search, body, func(s []byte) []byte {
m := string(s)
return []byte("<a href=\"/view/" + m + "\">" + m + "</a>")
})
fmt.Println(string(body))
}
您必须先调用 ReplaceAllFunc
,然后在同一正则表达式的函数调用 FindStringSubmatch
中再次调用。喜欢:
func (p parser) substituteEnvVars(data []byte) ([]byte, error) {
var err error
substituted := p.envVarPattern.ReplaceAllFunc(data, func(matched []byte) []byte {
varName := p.envVarPattern.FindStringSubmatch(string(matched))[1]
value := os.Getenv(varName)
if len(value) == 0 {
log.Printf("Fatal error substituting environment variable %s\n", varName)
}
return []byte(value)
});
return substituted, err
}
如果你想在ReplaceAllFunc
中获取组,你可以使用ReplaceAllString
获取子组。
package main
import (
"fmt"
"regexp"
)
func main() {
body := []byte("Visit this page: [PageName]")
search := regexp.MustCompile("\[([a-zA-Z]+)\]")
body = search.ReplaceAllFunc(body, func(s []byte) []byte {
// How can I access the capture group here?
group := search.ReplaceAllString(string(s), ``)
fmt.Println(group)
// handle group as you wish
newGroup := "<a href='/view/" + group + "'>" + group + "</a>"
return []byte(newGroup)
})
fmt.Println(string(body))
}
当有很多组时,你可以通过这种方式得到每个组,然后处理每个组和return想要的值。