-1

I have a string mixed with characters and numerals, but i want to increment the last character which happens to be a number, here is what i have, it works, but once i reach 10 rune goes to black since 10 decimal is zero, is there a better way to do this?

package main

import (
    "fmt"

)

func main() {
str := "version-1.1.0-8"
rStr := []rune(str)


last := rStr[len(rStr)-1]
rStr[len(rStr)-1] = last + 1


}

So this works for str := "version-1.1.0-8" = version-1.1.0-9 str := version-1.1.0-9 = version-1.1.0-

I understand why it is happening, but I dont know how to fix it

octain
  • 964
  • 3
  • 10
  • 24
  • 1
    Yes there is a better way. You should parse the version into all the parts every part will be an integer. Then you can increment the part you need. At the end you just create a new string. – apxp Nov 27 '18 at 19:20

1 Answers1

1

Your intention is to increment the number represented by the last rune, so you should do that: parse out that number, increment it as a number, and "re-encode" it into string.

You can't operate on a single rune, as once the number reaches 10, it can only be represented using 2 runes. Another issue is if the last number is 19, incrementing it needs to alter the previous rune (and not adding a new rune).

Parsing the numbers and re-encoding though is much easier than one might think.

You can take advantage of the fmt package's fmt.Sscanf() and fmt.Sprintf() functions. Parsing and re-encoding is just a single function call.

Let's wrap this functionality into a function:

const format = "version-%d.%d.%d-%d"

func incLast(s string) (string, error) {
    var a, b, c, d int
    if _, err := fmt.Sscanf(s, format, &a, &b, &c, &d); err != nil {
        return "", err
    }

    d++
    return fmt.Sprintf(format, a, b, c, d), nil
}

Testing it:

s := "version-1.1.0-8"

for i := 0; i < 13; i++ {
    var err error
    if s, err = incLast(s); err != nil {
        panic(err)
    }
    fmt.Println(s)
}

Output (try it on the Go Playground):

version-1.1.0-9
version-1.1.0-10
version-1.1.0-11
version-1.1.0-12
version-1.1.0-13
version-1.1.0-14
version-1.1.0-15
version-1.1.0-16
version-1.1.0-17
version-1.1.0-18
version-1.1.0-19
version-1.1.0-20
version-1.1.0-21

Another option would be to just parse and re-encode the last part, and not the complete version text. This is how it would look like:

func incLast2(s string) (string, error) {
    i := strings.LastIndexByte(s, '-')
    if i < 0 {
        return "", fmt.Errorf("invalid input")
    }

    d, err := strconv.Atoi(s[i+1:])
    if err != nil {
        return "", err
    }

    d++
    return s[:i+1] + strconv.Itoa(d), nil
}

Testing and output is the same. Try this one on the Go Playground.

icza
  • 389,944
  • 63
  • 907
  • 827