Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Split string and convert the substrings to integers in Go

I've got a single variable containing something like 1,2,3. These are actually three values, that I want to have in three variables called v1, v2, v3 (but not in an array).

Right now I'm doing this in the following way:

tmp := strings.Split(*w, ",")
sw, _ := strconv.Atoi(tmp[0])
rw, _ := strconv.Atoi(tmp[1])
pw, _ := strconv.Atoi(tmp[2])

This works, although it is very repetitive and does not feel right in Go.

What would be a cleaner way to solve this issue?

like image 328
Karol Babioch Avatar asked Nov 06 '17 16:11

Karol Babioch


People also ask

How do I split a string into number of substrings?

Use the Split method when the substrings you want are separated by a known delimiting character (or characters). Regular expressions are useful when the string conforms to a fixed pattern. Use the IndexOf and Substring methods in conjunction when you don't want to extract all of the substrings in a string.

How do you split a string in go?

The Split() method​ in Golang (defined in the strings library) breaks a string down into a list of substrings using a specified separator. The method returns the substrings in the form of a slice.

How can I split a string into an array of substrings?

The split() method splits a string into an array of substrings. The split() method returns the new array. The split() method does not change the original string. If (" ") is used as separator, the string is split between words.


2 Answers

Parsing data out of a string with a specific format and storing the parsed values into variables is a perfect task for and is easily done using fmt.Sscanf():

src := "1,2,3"

var a, b, c int

parsed, err := fmt.Sscanf(src, "%d,%d,%d", &a, &b, &c)
fmt.Println(parsed, err, a, b, c)

Output (try it on the Go Playground):

3 <nil> 1 2 3

Making it strict

As noted, this is very lenient, and will also successfully parse the "1,2,3," and "1,2,3,4" inputs. This may or may not be a problem (depending on your case). If you want to make it strict, you can apply this little trick:

var temp int
parsed, err := fmt.Sscanf(src+",1", "%d,%d,%d,%d", &a, &b, &c, &temp)

What we do is we append one more of the numbers that matches the input. If the original input does not end with a number (such as "1,2,3,"), parsing will fail with a non-nil error, and the above example gives:

3 expected integer 1 2 3

Try it on the Go Playground. Of course it will continue to parse "valid" inputs without any errors.

Note that this still accepts the input "1,2,3,4". We can "reduce" this trick to a single character, and we don't necessarily need a "target" variable to store it, it may simply be designated by the format string, like in this example:

parsed, err := fmt.Sscanf(src+"~", "%d,%d,%d~", &a, &b, &c)

We append a special character unlikely to happen in the input, and we expect that special character in the format string. Attempting to parse an invalid input (such as "1,2,3," or "1,2,3,4") will result in an error such as:

3 input does not match format 1 2 3

Try it on the Go Playground.

like image 105
icza Avatar answered Oct 20 '22 15:10

icza


If you're fine with a slice result, you could do it with slices:

tmp := strings.Split(*w, ",")
values := make([]int, 0, len(tmp))
for _, raw := range tmp {
    v, err := strconv.Atoi(raw)
    if err != nil {
        log.Print(err)
        continue
    }
    values = append(values, v)
}

Working playground example: https://play.golang.org/p/Y-QHmHP8Iy

like image 26
Adrian Avatar answered Oct 20 '22 16:10

Adrian