15

I want to replace a only one instance with a regex rather than all of them. How would I do this with Go's regexp library?

input: foobar1xfoobar2x
regex: bar(.)x
replacement: baz$1

ReplaceAllString output: foobaz1foobaz2
ReplaceOneString output: foobaz1foobar2x

5
  • That depends on the API. What are you using now? This may help us read the docs for you. Commented May 23, 2013 at 0:02
  • @Qtax, I'm using Go's regexp library Regexp.ReplaceAllString. An equivalent api for ReplaceOneString doesn't seem to exist. Commented May 23, 2013 at 0:07
  • 1
    You could try the following as a workaround (didn't test it thoroughly) Commented May 23, 2013 at 0:11
  • @HamZaDzCyberDeV, that solves this one case, but I'm looking for a general solution. Commented May 23, 2013 at 0:17
  • 2
    Actually that solution is very generic. It will always replace the first match with your replacement and leave everything after untouched. Commented May 23, 2013 at 0:40

3 Answers 3

10

In general, if you use lazy match and use anchors for beginning and end, you can have the replace first behavior:

replace `^(.*?)bar(.*)$` with `$1baz$2`.

Example:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    src := "foobar1xfoobar2x"
    pat := regexp.MustCompile("^(.*?)bar(.*)$")
        repl := "${1}baz$2"
    output := pat.ReplaceAllString(src, repl)
    fmt.Println(output)
}

Output

foobaz1xfoobar2x
Sign up to request clarification or add additional context in comments.

2 Comments

you need to curly the group variables if they make valid identifier names with the following characters, see the updated answer
Wouldn't appending a (.*) to the end of the regex along with a suitable substitution var be enough?
6

I had the same problem. The most clean solution I've come up with:

package main

import (
    "fmt"
    "regexp"
    "strings"
)

func main() {
    re, _ := regexp.Compile("[a-z]{3}")
    s := "aaa bbb ccc"

    // Replace all strings
    fmt.Println(re.ReplaceAllString(s, "000"))

    // Replace one string
    found := re.FindString(s)
    if found != "" {
        fmt.Println(strings.Replace(s, found, "000", 1))
    }
}

Running:

$ go run test.go 
000 000 000
000 bbb ccc

1 Comment

This does not work correctly when the regexp is complex enough, e.g. matching on word boundaries will cause this to incorrectly replace an earlier part of the string: go.dev/play/p/gWejkYZ8dB6
3

I cound't use accepted solution because my pattern was very complicated. I ended up with using ReplaceAllStringFunc : https://play.golang.org/p/ihtuIU-WEYG

package main

import (
    "fmt"
    "regexp"
)

var pat = regexp.MustCompile("bar(.)(x)")

func main() {
    src := "foobar1xfoobar2x"
    flag := false
    output := pat.ReplaceAllStringFunc(src, func(a string) string {
        if flag {
            return a
        }
        flag = true
        return pat.ReplaceAllString(a, "baz$1$2")
    })
    fmt.Println(output)
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.