Home > Software design >  Regular expression to capture a group that is optionally present in Go?
Regular expression to capture a group that is optionally present in Go?

Time:01-15

I'm trying to write a regular expression that in a string representing Go code will replace the name of a type, say Bar, with an updated name, say FooBar, but only where it appears as the type of a field in another struct or as an array of that type. So I'd like to convert for example

type Foo struct {
    Bar  Bar
    Baz  []Bar
    Bars []Bar
}

into

type Foo struct {
    Bar  FooBar
    Baz  []FooBar
    Bars []FooBar
}

So far, I've managed to convert the array field types using this ReplaceAllString:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`(\w )(\s )\[\]Bar`)

    s := `type Foo struct {
    Bar  Bar
    Baz  []Bar
    Bars []Bar
}`

    fmt.Println(re.ReplaceAllString(s, `$1$2[]FooBar`))
}

which produces

type Foo struct {
    Bar  Bar
    Baz  []FooBar
    Bars []FooBar
}

What is missing is the replacement of Bar as the type of the first field, also named Bar. I've tried making the [] optional like so,

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`(\w )(\s )(\[\])?Bar`)

    s := `type Foo struct {
    Bar  Bar
    Baz  []Bar
    Bars []Bar
}`

    fmt.Println(re.ReplaceAllString(s, `$1$2$3FooBar`))
}

but this produces an output where all of the field types are missing:

type Foo struct {
    Bar  
    Baz  
    Bars 
}

Can someone spot what is wrong here? (I could use a two-pass approach with two different regular expressions, but would prefer to achieve this in one go).

CodePudding user response:

It turns out the third reference needs to be ${3}, not $3:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`(\w )(\s )(\[\])?Bar`)

    s := `type Foo struct {
    Bar  Bar
    Baz  []Bar
    Bars []Bar
}`

    fmt.Println(re.ReplaceAllString(s, `$1$2${3}FooBar`))
}

which produces the desired result

type Foo struct {
    Bar  FooBar
    Baz  []FooBar
    Bars []FooBar
}

CodePudding user response:

depending on your situation, gofmt might be a better option:

> gofmt -r 'Bar -> FooBar' hello.go
package hello

type Foo struct {
        FooBar FooBar
        Baz    []FooBar
        Bars   []FooBar
}

https://godocs.io/cmd/gofmt

  • Related