Related
I have 2 yaml files that I've exported to 2 different map variables. My yaml files have this example of format:
file1.yaml
a: b
c: d
e:
- f
- g
x:
- y
file2.yaml
m: n
c: d
x:
- y
- z
I've unmarshalled the yaml files into structs. My goal is to now compare the 2 maps, and only output the difference found in file2.yaml. So far I have something simple:
type ParametersYaml struct {
Parameters Params `yaml:"parameters""`
}
type Params map[string]interface{}
var pParam ParametersYaml
var sParam ParametersYaml
func Extractor(primaryYaml, secondaryYaml string) error {
primaryOpenedFile, err := fileOpener(primaryYaml)
secondaryOpenedFile, err := fileOpener(secondaryYaml)
err = yamlParser(primaryOpenedFile, &pParam)
err = yamlParser(secondaryOpenedFile, &sParam)
if err != nil {
return err
}
compare(pParam, sParam)
return err
}
func fileOpener(file string) ([]byte, error) {
f, err := ioutil.ReadFile(file)
return f, err
}
func yamlParser(fileObject []byte, param *ParametersYaml) error {
err := yaml.Unmarshal(fileObject, ¶m)
return err
}
func compare(pMarshalled, sMarshalled ParametersYaml) {
for s, sv := range sMarshalled.Parameters {
for p, pv := range pMarshalled.Parameters {
if s == p && sv == pv {
break
} else if s == p && sv != pv {
fmt.Printf("%s: %s,\n", s, sv)
break
} else if _, ok := pMarshalled.Parameters[s]; !ok {
fmt.Printf("%s: %s,\n", s, sv)
break
}
}
}
}
But it can't compare values with lists since the type is of interface{}.
There exists https://github.com/sters/yaml-diff which does the same thing you're intending to achieve.
How can I change the code instead of showing it (fmt.Printf) to execute a command (exec.Command)
Now I have this:
// Print keys
fmt.Printf("%x %34s %34s\n", padded, uaddr.EncodeAddress(), caddr.EncodeAddress())
How to give a variable value to 'g' and 'h':
v := "cmd"
n := "/C"
a := "testcmd"
b := "-connect=127.0.0.1"
c := "-port=3333"
d := "-user=username"
e := "-password=password"
f := "importaddress"
g := "AddressHere"
h := "MoreInfo"
z := exec.Command(v, n, a, b, c, d, e, f, g, h)
if err := z.Run(); err != nil {
fmt.Println("Error: ", err)
}
I need to give this variable valie:
h := fmt.Printf("%x\n", padded)
g := fmt.Printf("%34s\n", uaddr.EncodeAddress())
g := fmt.Printf("%34s\n", caddr.EncodeAddress())
execute the command twice with different variables
You can use fmt.Sprintf()
Example:
g := fmt.Sprintf("%s", uaddr.EncodeAddress())
Sprintf formats according to a format specifier and returns the resulting string. You can then use this same value for your variables.
I would like to read a slice of strings representing hexadecimal numbers, and decode them to a slice of byte slices ([]string --> [][]byte). This is my code so far:
func (self *algo_t) decode_args(args []string) ([][]byte, error) {
var data [][]byte
for i := uint32(0); i < self.num_args; i++ {
data = make([][]byte, self.num_args)
tmp, err := hex.DecodeString(args[i])
fmt.Printf("i = %d\ttmp = %x\n", i, tmp)
data[i] = make([]byte, len(tmp))
copy(data[i], tmp)
if err != nil {
fmt.Fprintf(os.Stderr, "Error decoding hex string %s: %s\n", args[i], err.Error())
return nil, err
}
}
fmt.Printf("line 69\tdata[0] = %x\tdata[1] = %x\tdata[2] = %x\n",data[0], data[1], data[2])
return data, nil
}
calling this code and passing args = []string{"010203","040506","070809"} yields the following output:
i = 0 tmp = 010203
i = 1 tmp = 040506
i = 3 tmp = 070809
line 69 data[0] = data[1] = data[2] = 070809
Presumably the function returns [][]byte{[]byte{}, []byte{}, []byte{0x07, 0x08, 0x09}}.
I understand that this is because of the pointer behavior of Go; what is the best practice for doing a deep copy of this kind?
For example,
package main
import (
"encoding/hex"
"fmt"
)
// Decode hex []string to [][]byte
func decode(s []string) ([][]byte, error) {
b := make([][]byte, len(s))
for i, ss := range s {
h, err := hex.DecodeString(ss)
if err != nil {
err = fmt.Errorf(
"Error decoding hex string %s: %s\n",
ss, err.Error(),
)
return nil, err
}
b[i] = h
}
return b, nil
}
func main() {
s := []string{"010203", "040506", "070809"}
fmt.Println(s)
b, err := decode(s)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(b)
}
s = []string{"ABCDEF", "012345", "09AF"}
fmt.Println(s)
b, err = decode(s)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(b)
}
s = []string{"01", "123XYZ"}
fmt.Println(s)
b, err = decode(s)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(b)
}
}
Output:
[010203 040506 070809]
[[1 2 3] [4 5 6] [7 8 9]]
[ABCDEF 012345 09AF]
[[171 205 239] [1 35 69] [9 175]]
[01 123XYZ]
Error decoding hex string 123XYZ: encoding/hex: invalid byte: U+0058 'X'
There is a package built specifically to handle deep copy: http://godoc.org/code.google.com/p/rog-go/exp/deepcopy
You can look at the source here: https://code.google.com/p/rog-go/source/browse/exp/deepcopy/deepcopy.go. It covers copying slices and pointers, so it should cover your case.
I am trying to gzip a slice of bytes using the package "compress/gzip". I am writing to a bytes.Buffer and I am writing 45976 bytes, when I am trying to uncompress the content using a gzip.reader and then reader function - I find that the not all of the content is recovered. Is there some limitations to bytes.buffer? and is it a way to by pass or alter this? here is my code (edit):
func compress_and_uncompress() {
var buf bytes.Buffer
w := gzip.NewWriter(&buf)
i,err := w.Write([]byte(long_string))
if(err!=nil){
log.Fatal(err)
}
w.Close()
b2 := make([]byte, 80000)
r, _ := gzip.NewReader(&buf)
j, err := r.Read(b2)
if(err!=nil){
log.Fatal(err)
}
r.Close()
fmt.Println("Wrote:", i, "Read:", j)
}
output from testing (with a chosen string as long_string) would give
Wrote: 45976, Read 32768
Continue reading to get the remaining 13208 bytes. The first read returns 32768 bytes, the second read returns 13208 bytes, and the third read returns zero bytes and EOF.
For example,
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io"
"log"
)
func compress_and_uncompress() {
var buf bytes.Buffer
w := gzip.NewWriter(&buf)
i, err := w.Write([]byte(long_string))
if err != nil {
log.Fatal(err)
}
w.Close()
b2 := make([]byte, 80000)
r, _ := gzip.NewReader(&buf)
j := 0
for {
n, err := r.Read(b2[:cap(b2)])
b2 = b2[:n]
j += n
if err != nil {
if err != io.EOF {
log.Fatal(err)
}
if n == 0 {
break
}
}
fmt.Println(len(b2))
}
r.Close()
fmt.Println("Wrote:", i, "Read:", j)
}
var long_string string
func main() {
long_string = string(make([]byte, 45976))
compress_and_uncompress()
}
Output:
32768
13208
Wrote: 45976 Read: 45976
Use ioutil.ReadAll. The contract for io.Reader says it doesn't have to return all the data and there is a good reason for it not to to do with sizes of internal buffers. ioutil.ReadAll works like io.Reader but will read until EOF.
Eg (untested)
import "io/ioutil"
func compress_and_uncompress() {
var buf bytes.Buffer
w := gzip.NewWriter(&buf)
i,err := w.Write([]byte(long_string))
if err!=nil {
log.Fatal(err)
}
w.Close()
r, _ := gzip.NewReader(&buf)
b2, err := ioutil.ReadAll(r)
if err!=nil {
log.Fatal(err)
}
r.Close()
fmt.Println("Wrote:", i, "Read:", len(b2))
}
If the read from gzip.NewReader does not return the whole expected slice. You can just keep re-reading until you have recieved all the data in the buffer.
Regarding you problem where if you re-read the subsequent reads did not append to the end of the slice, but instead at the beginning; the answer can be found in the implementation of gzip's Read function, which includes
208 z.digest.Write(p[0:n])
This will result in an "append" at the beginning of the string.
This can be solves in this manner
func compress_and_uncompress(long_string string) {
// Writer
var buf bytes.Buffer
w := gzip.NewWriter(&buf)
i,err := w.Write([]byte(long_string))
if(err!=nil){
log.Fatal(err)
}
w.Close()
// Reader
var j, k int
b2 := make([]byte, 80000)
r, _ := gzip.NewReader(&buf)
for j=0 ; ; j+=k {
k, err = r.Read(b2[j:]) // Add the offset here
if(err!=nil){
if(err != io.EOF){
log.Fatal(err)
} else{
break
}
}
}
r.Close()
fmt.Println("Wrote:", i, "Read:", j)
}
The result will be:
Wrote: 45976 Read: 45976
Also after testing with a string of 45976 characters i can confirm that the output is in exactly the same manner as the input, where the second part is correctly appended after the first part.
Source for gzip.Read: http://golang.org/src/pkg/compress/gzip/gunzip.go?s=4633:4683#L189
I have a line containing 3 numbers that I want to read from stdin with fmt.Scanln() but this code won't work:
X := make([]int, 3)
fmt.Scanln(X...)
fmt.Printf("%v\n", X)
I get this error message:
cannot use X (type []int) as type []interface {} in function argument
I don't get it.
Idiomatic Go would be:
func read(n int) ([]int, error) {
in := make([]int, n)
for i := range in {
_, err := fmt.Scan(&in[i])
if err != nil {
return in[:i], err
}
}
return in, nil
}
interface{} means nothing. Please don't use it if you don't have to.
For example,
package main
import "fmt"
func intScanln(n int) ([]int, error) {
x := make([]int, n)
y := make([]interface{}, len(x))
for i := range x {
y[i] = &x[i]
}
n, err := fmt.Scanln(y...)
x = x[:n]
return x, err
}
func main() {
x, err := intScanln(3)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%v\n", x)
}
Input:
1 2 3
Output:
[1 2 3]
I think the the correct version should be
X := make([]int, 3)
fmt.Scanln(&X[0], &X[1], &X[2])
fmt.Printf("%v\n", X)
This error message occurs b/c there's no reasonable way to convert []int to []interface{}. Note, this is in reference to a slice. So the syntax your using is correct, but fmt.Scanln expects []interface{}. This has implications outside of pkg fmt.
The reason I've seen given for this is due to Go giving you control over memory layout so it currently has no reasonable way to do the slice conversion. This means you'll need to do the conversion manually before passing it to a function expecting the slice of a given type. For example:
package main
import (
"fmt"
)
func main() {
x := make([]int, 3)
y := make([]interface{}, 3)
y[0] = x[0]
y[1] = x[1]
y[2] = x[2]
fmt.Println(y...)
}
Or something a little more general:
x := make([]int, 3)
y := make([]interface{}, len(x))
for i, v := range x {
y[i] = v
}
fmt.Println(y...)
Regarding your specific issue, see the following:
x := make([]*int, 3)
for i := range x {
x[i] = new(int)
}
y := make([]interface{}, 3)
for i, v := range x {
y[i] = v
}
if _, err := fmt.Scanln(y...); err != nil {
fmt.Println("Scanln err: ", err)
}
for _, v := range y {
val := v.(*int)
fmt.Println(*val)
}
I saw in a comment you said the lines can have different lengths. In that case
you can implement your own fmt.Scanner:
package main
import (
"bytes"
"fmt"
)
type slice struct {
tok []int
}
func (s *slice) Scan(state fmt.ScanState, verb rune) error {
tok, err := state.Token(false, func(r rune) bool { return r != '\n' })
if err != nil { return err }
if _, _, err := state.ReadRune(); err != nil {
if len(tok) == 0 {
panic(err)
}
}
b := bytes.NewReader(tok)
for {
var d int
_, err := fmt.Fscan(b, &d)
if err != nil { break }
s.tok = append(s.tok, d)
}
return nil
}
func main() {
var s slice
fmt.Scan(&s)
fmt.Println(s.tok)
}
https://golang.org/pkg/fmt#Scanner