firasdib / Regex101

This repository is currently only used for issue tracking for www.regex101.com
3.26k stars 199 forks source link

Golang generated code is not working as expected #1353

Open kpym opened 4 years ago

kpym commented 4 years ago

Code Generator Language

Go

Code Snippet

I want to replace A(.)C in ABC with C${1}A (the result should be CBA). The current code is


package main

import (
    "regexp"
    "fmt"
)

func main() {
    var re = regexp.MustCompile(`^A(.)C$`)
    var str = []byte(`ABC`)
    var substitution = []byte("C${1}A")
    var i = 0
    var count = 1

    str = re.ReplaceAllFunc(str, func(s []byte) []byte {
        if count < 0 {
            return substitution
        } else if i < count {
            i += 1

            return substitution
        }

        return s
    })

    fmt.Println(string(str))
}

which is not working.

The desired code is

package main

import (
    "regexp"
    "fmt"
)

func main() {
    var re = regexp.MustCompile(`^A(.)C$`)
    var str = []byte(`ABC`)
    var substitution = []byte("C${1}A")

    str = re.ReplaceAll(str, substitution)

    fmt.Println(string(str))
}
working-name commented 4 years ago

Hi! Can you please elaborate on "not working"? Do you get an error/message? (I've never done anything in go)

Update: nevermind, ran in the Go Playground, output of first seems literal but have no knowledge of why. Proposed code seems to be just fine with one or more replacements within the string.

Thank you!

kpym commented 4 years ago

You can check the result (C${1}A) in the online playground.

The code is doing "string" replacement, not "regex" one.

You can also check the code that I suggest in the same online playground.

firasdib commented 4 years ago

Hmm, it looks like you've compiled a non-global regex, is that correct? In that scenario, only the first occurrence should be replaced. The first code examples (tries) to do that, while the second does not (unless I'm misinterpreting something).

Perhaps you can help correct the whole code generator for golang, if there are cases where it is incorrect? You can view the four different scenarios here:

Non-global substitution: https://regex101.com/r/rRAG2X/1/codegen?language=golang Global substitution: https://regex101.com/r/rRAG2X/2/codegen?language=golang Non-global match: https://regex101.com/r/rRAG2X/3/codegen?language=golang Global match: https://regex101.com/r/rRAG2X/4/codegen?language=golang

Thanks in advance!

kpym commented 4 years ago

You are right, the only problem is in the case of non-global substitution. Here is my proposal.

package main

import (
    "fmt"
    "regexp"
)

func main() {
    var re = regexp.MustCompile(`A(.)C`)
    var str = "ABCABC"
    var substitution = `C${1}A`
    var count = 1 // nagative counter is equivalent to global case (replace all)

    str = re.ReplaceAllStringFunc(str, func(s string) string {
        if count == 0 {
            return s
        }

        count -= 1
        return re.ReplaceAllString(s, substitution)
    })

    fmt.Println(string(str))
}

What I have done :

You can check and play with this code in the golang playground.

kpym commented 3 years ago

I have made a proposal to manage this case easily in Go, but it was not accepted (for backward compatibility reasons). So putting the right code generator may help Go developers to write non-global replace properly.

firasdib commented 3 years ago

I will try to get around to this soon.

kpym commented 3 years ago

@firasdib thanks. Here is an alternative code that introduce the missing ReplaceString function with limiting parameter n.

package main

import (
    "fmt"
    "regexp"
)

func ReplaceString(src, search, repl string, n int) string {

    var re = regexp.MustCompile(search)

    src = re.ReplaceAllStringFunc(src, func(s string) string {
        if n == 0 {
            return s
        }

        n -= 1
        return re.ReplaceAllString(s, repl)
    })

    return src
}

func main() {
    var re = `A(.)C`
    var str = "ABCABC"
    var substitution = `C${1}A`

    fmt.Println(ReplaceString(str, re, substitution, 1))
}

This code in Google Playground.

You can use this one or the code from my previous comment.

Ouims commented 3 years ago

Did you ever fix this @firasdib ?