如何从regexp.ReplaceAllFunc访问捕获组?

Sau*_*lva 6 go

如何从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))
}
Run Code Online (Sandbox Code Playgroud)

目标是替换[PageName]<a href="/view/PageName">PageName</a>.

这是Writing Web Applications Go教程底部"其他任务"部分下的最后一项任务.

tum*_*dum 5

我同意在你的功能内部访问捕获组是理想的,我不认为这是可能的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))
}
Run Code Online (Sandbox Code Playgroud)

编辑

我还知道如何做你想做的事.您需要知道的第一件事是您可以使用语法指定非捕获组(?:re),其中re是您的正则表达式.这不是必需的,但会减少不感兴趣的比赛数量.

接下来要知道的是regexp.FindAllSubmatcheIndex.它将返回切片切片,其中每个内部切片表示给定匹配正则表达式的所有子匹配的范围.

有了这两件事,你可以构建一些通用的解决方案:

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))
}
Run Code Online (Sandbox Code Playgroud)


小智 4

如果要获取 中的组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), `$1`)

        fmt.Println(group)

        // handle group as you wish
        newGroup := "<a href='/view/" + group + "'>" + group + "</a>"
        return []byte(newGroup)
    })

    fmt.Println(string(body))
}
Run Code Online (Sandbox Code Playgroud)

当有很多组时,您可以通过这种方式获取每个组,然后处理每个组并返回所需的值。