I have a JSON String as {1}
or possibly {2}
and I need to parse it and obtain the integer parsed.
I know I'm doing this incorrectly, but here's what I have thus far:
package main
import (
"fmt"
"encoding/json"
)
func main(){
jsonStr:="{1}"
jsonData:=[]byte(jsonStr)
var v uint
json.Unmarshal(jsonData, &v)
data:=v
fmt.Println(data)
}
In this example, the data
variable should contain the integer value of 1 or 2 if the jsonStr
value is {2}
From my experience with JSON and Go I usually use a struct and pass that into the Unmarshalling function, but i cannot make a struct out of this data response.
I looked at the API Documentation and found no solution for a string parse without a struct
This seemed to work for me:
import "regexp"
re:=regexp.MustCompile("[0-9A-Za-z]+")
val:=re.FindAllString(jsonStr,-1)[0]
Some alternatives to regexes since they are resource heavy and tend to be slower than other solutions, errors are ignored for brevity. In prod they wouldn't be.
package main
import (
"fmt"
"strconv"
)
func main() {
str := "{1}"
num, _ := strconv.ParseInt(string(str[1]), 10, 64)
fmt.Println(num)
}
or something more robust that doesn't care about the number of digits in the {}
field.
package main
import (
"fmt"
"strconv"
)
func main() {
str := "{341}"
num, _ := strconv.ParseInt(string(str[1:len(str)-1]), 10, 64)
fmt.Println(num)
}
Small benchmark image showing how much slower regexes are than other solutions. They should be used when other options are available or if performance isn't an issue/concern.
Even something like this will out perform a regex
var n string
for _, r := range str {
if unicode.IsDigit(r) {
n += string(r)
}
}
code for benchmark https://goplay.space/#PLMtSrMTN9k
As noted by commenters, your example strings are not valid JSON since brace-delimited JSON documents must be objects with a list of key-value pairs (e.g. {"x":1}
, and numbers are plain (e.g. 2
). However, this simple notation of a "brace enclosed integer" could easily be parsed a number of ways, ultimately by checking the syntax of OPEN_BRACE, DIGIT+, CLOSE_BRACE
.
The example code below checks that the first rune of a given string is an open brace {
, the last is a close brace }
, and everything in between can be parsed as an integer using strconv.ParseInt(...)
:
func main() {
ss := []string{"{1}", "{2}", "{-123}", "{foo}", "{10", "20}", "30"}
for _, s := range ss {
x, err := parseBraceNumber(s)
fmt.Printf("s=%-10qx=%-10derr=%v
", s, x, err)
}
// s="{1}" x=1 err=<nil>
// s="{2}" x=2 err=<nil>
// s="{-123}" x=-123 err=<nil>
// s="{foo}" x=0 err=invalid brace number "{foo}"
// s="{10" x=0 err=invalid brace number "{10"
// s="20}" x=0 err=invalid brace number "20}"
// s="30" x=0 err=invalid brace number "30"
}
func parseBraceNumber(s string) (int64, error) {
if len(s) < 3 || s[0] != '{' || s[len(s)-1] != '}' {
return 0, fmt.Errorf("invalid brace number %q", s)
}
x, err := strconv.ParseInt(s[1:len(s)-1], 10, 64)
if err != nil {
return 0, fmt.Errorf("invalid brace number %q", s)
}
return x, nil
}
Of course, other strategies are possible (e.g. using regular expressions) and ultimately it is up to you to decide what implementation is best for your use case.