GoLang parsing string to struct [closed] - go

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
This post was edited and submitted for review 1 year ago and failed to reopen the post:
Needs details or clarity Add details and clarify the problem by editing this post.
Improve this question
How do I convert a string to a structure?
The line looks like this: Name[data1] Name2[data1 data2 data3] Name3[data1 data2] ...
The data can be of type Int, String, or Float. In general, this is not important, you can write everything as string.
Data in brackets is separated by a space
What I got using regexp:
func Parse() {
str := "Version[2f0] Terminal[10002] Machine[10.1.1.1] DH[0.137%] Temp[45] Fan[0] Vo[4074 4042 4058 4098] CRC[0 0 0 0]"
j := make(map[string][]string)
re, err := regexp.Compile(`(?P<Name>[^ \[]*)\[(?P<Value>[^\]]*)`)
if err != nil {
log.Fatal(err)
}
res := re.FindAllSubmatch([]byte(str), -1)
for _, match := range res {
j[string(match[1])] = strings.Split(string(match[2]), " ")
}
log.Printf("%+v", j)
}
Could there be a more elegant way using json.Unmarshal?

You need to define a specific format for the serializing the data. A key part of that will be how to encode specific special characters, such as the [ and ]. You generally do not want to do this.
If you want to use any string as a temporary textual representation of your data and the format doesn't matter, you can just use JSON and use json.Marshal() and json.Unmarshal().
I'm not sure what you are trying to achieve (what's this struct data? what generated it? why are you trying to decode it into a struct?) but it seems that going through the fundamentals might be helpful:
https://en.wikipedia.org/wiki/Serialization will tell you what that is
https://betterprogramming.pub/serialization-and-deserialization-ba12fc3fbe23 is a very short guide that will give you the very basics (in JavaScript)
I already mentioned json.Marshal and json.Unmarshal - reading their docs in the standard library will be helpful as well.
I'm sure you can google the more in-depth articles when you identify what you need to know for your specific purposes.

If you're free to use any tool you like, a regular expression might make this fairly easy.
(?P<Name>\[^\[\]*)\[(?P<Values>\[^\]\]*)\]
That matches each of the named value sets.
and then you could split the Values group at the spaces with string.Split
To create a dynamic struct you'd need to use reflection. Avoid reflection, though, as you learn Go. A struct in Go is unlike an object in say Javascript or Python, where fields are dynamic at runtime. Go structs are meant to have static fields.
For this purpose, a map[string][]string would be a more appropriate type. The key would be the Name fields, and the value would be the data fields.

Related

generate a yaml file dynamically in golang

I want to generate a yaml file using a struct's yaml tags, but I want to ignore the omitempty tags. So I figured I should go over the struct recursively with reflection, and get the information using Tag.GetTag("yaml").
This is fine, but it leaves me with the task of creating a yaml with this information.
I started writing this -
const Indent = " "
const NL = ":\n"
type Yaml struct {
Simple []string
Slices [][]Yaml
Nested map[string] *Yaml
}
But I actually hope there is a useful library to do this, as it seems like a relatively common task to do. Unfortunately,a search in Google didn't find anything.
Does such a library exist?
Thanks,

Is there a difference between array and array[:] in Go?

boltdb/bolt is an embedded key/value database for Go.
When I read the source code of bolt, I find the following code,
p := db.pageInBuffer(buf[:], pgid(i))
from: https://github.com/boltdb/bolt/blob/master/db.go#L350
But I can not get the reason why it use buf[:] instead of buf, can anyone provide an explanation for this code style?

Best way to marshal map to struct fields in GO

I want to know which is the best way to create instances of a certain struct based on a map[string]string
My app should process huge files in CSV format and should create an instance of a struct for each row of the file.
I'm already using the encoding/csv/Reader from golang to read the CSV file and create an instance of map[string]string for each row in the file.
So given this file:
columnA, columnB, columnC
a, b, c
My own reader implementation will return this map (each row values with the header):
myMap := map[string]string{
"columnA": "a",
"columnB": "b",
"columnC": "c",
}
(this is just an example in real life the file contains a lot of columns and rows)
so.. at this point I need to create an instance of the struct that is related with the row contents, let say:
type MyStruct struct {
AColumn string
BColumn string
CColumn string
}
My question is what could be the best way to create the instance of the struct using the given map, I have already implemented a version that just copy each value from the map to the struct but the code ended up being very long and tedious:
s := &MyStruct{}
s.AColumn := m["columnA"]
s.AColumn := m["columnB"]
s.AColumn := m["columnC"]
...
I also consider using this library https://github.com/mitchellh/mapstructure but I don't know if using reflection could be the best approach considering that the file is huge and will be using reflection for each row.
Maybe there is no other option but I'm asking just in case someone knows a better approach.
Thanks in advance.
I would say that the idiomatic Go way would be just populating the struct's fields from your map. Go favors explicitness this approach is the more direct and the easiest to read. In other words, your approach is correct.
You could make it slightly nicer by initializing the struct directly:
s := &MyStruct{
AColumn: m["columnA"],
BColumn: m["columnB"],
CColumn: m["columnC"],
}
Now, if your structure has 100s of fields (which is an odd design choice), you may want to leverage some code generation. Otherwise, just go with the straightforward code - it's the best approach in the long term.
I already posted a library that I made for some stuff I have needed sometimes, I've made a MapToStruct fews months ago, I pushed that today to share with you the full library. The library is based in the usage of reflect, I still testing and implementing stuff, you will find some odd comments and these kind of things.
https://github.com/FedeMFernandez/goscript
I Hope it is useful

How to convert a nested hash which is in string back into a hash? [duplicate]

This question already has answers here:
How do I convert a String object into a Hash object?
(16 answers)
Closed 4 years ago.
I stored my nested hash in a file, and while retrieving it, I want to it back in a hash form instead of string. When I read a file it will give me a string and then how can I parse it back to a hash.
This is the string hash in the file:
{"SONGS"=>{1=>["2018-05-29 18:19:14 +0530", "HAPPY", "Meri Sapnon Ki Rani"]}}
Already in SO.
WARNING SECURITY RISK!
For your string you need to pass to eval, but this is a SECURITY RISK
string = '{"SONGS"=>{1=>["2018-05-29 18:19:14 +0530", "HAPPY", "Meri Sapnon Ki Rani"]}}'
p eval(string).class
If you need to store data structures in files, I suggest you to take a look at YAML module. Look at this post, for example.
As suggested in comments:
Consider also security concerns, look this post.
Consider to change a little bit the string syntax to use a JSON structure. See below.
Use of JSON:
require 'json'
json_string = '{"songs":{"1":{"date": "2018-05-29 18:19:14 +0530", "title":"HAPPY", "name":"Meri Sapnon Ki Rani"}}}'
p JSON::parse(json_string).class

Is there a way to ensure that all data in a yaml string was parsed?

For testing, I often see go code read byte slices, which are parsed into structs using yaml, for example here:
https://github.com/kubernetes/kubernetes/blob/master/pkg/util/strategicpatch/patch_test.go#L74m
I just got bitten by not exporting my field names, resulting in an empty list which I iterated over in my test cases, thus assuming that all tests were passing (in hindsight, that should have been a red flag :)). There are other errors which are silently ignored by yaml unmarshaling, such as a key being misspelled and not matching a struct field exactly.
Is there a way to ensure that all the data in the byte slice was actually parsed into the struct returned by yaml.Unmarshal? If not, how do others handle this situation?
go-yaml/yaml
For anyone searching for a solution to this problem, the yaml.v2 library has an UnmarshalStrict method that returns an error if there are keys in the yaml document that have no corresponding fields in the go struct.
import yaml "gopkg.in/yaml.v2"
err := yaml.UnmarshalStrict(data, destinationStruct)
BurntSushi/toml
It's not part of the question, but I'd just like to document how to achieve something similar in toml:
You can find if there were any keys in the toml file that could not be decoded by using the metadata returned by the toml.decode function.
import "github.com/BurntSushi/toml"
metadata, err := toml.Decode(data, destinationStruct)
undecodedKeys := metadata.Undecoded()
Note that metadata.Undecoded() also returns keys that have not been decoded because of a Primitive value. You can read more about it here.
Json
The default go json library does not support this currently, but there is a proposal ready to be merged. It seems that it will be a part of go 1.10.

Resources