2

In Ruby, I'm using the string.unpack method to decode some data. I'm migrating this code into a Golang app, however I can't find a corresponding method in the standard library?

The ruby code is: str.unpack('>LLLff')

What is the best way to implement this in Go?


Example data:

]\x00\x00@\x00\x8C\xD2\x00\x00\x00\x00\x00\x00\x00\x00h.\x9FAjK\x8FG\xC0T\x87UX\xA1CH\xB7\x80\x82}\xBB\xF9\x8F\xBAcqF{\xE31/Zx\xC0\x04\xFF\b\xA0\xBD\a\x9E\x0F\x14c+\b\xD3\xE8\xE1\xC2\x1C7\xBCmd/j\xC1H\x191~\x91F\b5-\x8A\x9F(\\\xF1\x16/\x0F\xEA\xD9\x94rV\xEC\xBB\xCB\x12qJ\x05\b\x04 {R\xB8\xA4\xA9\xD0)v\x97<\xCA\x92\xB6U\b)\x1D\x1D\xF1\x00\xE4U\x8DB\x16/v\xEC[bLTW\xB2\xFB\x0F\x91\x05\xAA\x9C\xBD\x8E\x1A\xFB\xDFUJ\xB8\xDE\xF5m\xC8Z\xC1\v\\|\r;\xB6\xE6\xA6\x13o\x91\xE1\xBA\x9An\x8B\x01W\xB9\"\x12+\x9B[\xC7\xCD\xC2O+\f^|\xE1G\x86.%m\xB2x\xF1j\e\"\xE41Bu_\x16J\xE4M\x7F\xC5U[\xB9\xD0\xC7\xECu\xE53\xB4)\xD5\x80|\xB7.\xD2\f\xF3\x16\x8B\xE3\x13\x81\x02:5\x88\x0F

Should map to: [1073741917, 13798400, 0, 2.4178516392292583e+24, 5.851859700165677e+25]

Ben Toogood
  • 469
  • 4
  • 9
  • 2
    Possible duplicate of [How do I unpack various form of integers in a byte buffer in Golang?](https://stackoverflow.com/questions/12357865/how-do-i-unpack-various-form-of-integers-in-a-byte-buffer-in-golang) – Leon Oct 07 '18 at 21:04
  • I don't think its quite a duplicate, and it will be useful for those coming from Ruby to see it answered in this context. – Will Oct 08 '18 at 00:42

1 Answers1

4

Try this:

package main

import (
    "bytes"
    "encoding/binary"
    "log"
)

type UnpackedThing struct {
    First  uint32
    Second uint32
    Third  uint32

    Fourth float32
    Fifth  float32
}

func main() {
    input := bytes.NewBufferString("]\x00\x00@\x00\x8C\xD2\x00\x00\x00\x00\x00\x00\x00\x00h.\x9FAjK\x8FG\xC0T\x87UX\xA1CH\xB7\x80\x82}\xBB\xF9\x8F\xBAcqF{\xE31/Zx\xC0\x04\xFF\b\xA0\xBD\a\x9E\x0F\x14c+\b\xD3\xE8\xE1\xC2\x1C7\xBCmd/j\xC1H\x191~\x91F\b5-\x8A\x9F(\\\xF1\x16/\x0F\xEA\xD9\x94rV\xEC\xBB\xCB\x12qJ\x05\b\x04 {R\xB8\xA4\xA9\xD0)v\x97<\xCA\x92\xB6U\b)\x1D\x1D\xF1\x00\xE4U\x8DB\x16/v\xEC[bLTW\xB2\xFB\x0F\x91\x05\xAA\x9C\xBD\x8E\x1A\xFB\xDFUJ\xB8\xDE\xF5m\xC8Z\xC1\v\\|\r;\xB6\xE6\xA6\x13o\x91\xE1\xBA\x9An\x8B\x01W\xB9\"\x12+\x9B[\xC7\xCD\xC2O+\f^|\xE1G\x86.%m\xB2x\xF1j\x1B\"\xE41Bu_\x16J\xE4M\x7F\xC5U[\xB9\xD0\xC7\xECu\xE53\xB4)\xD5\x80|\xB7.\xD2\f\xF3\x16\x8B\xE3\x13\x81\x02:5\x88\x0F")
    var unpacked UnpackedThing

    err := binary.Read(input, binary.LittleEndian, &unpacked)
    if err != nil {
        log.Fatal(err)
    }

    log.Printf("[%d, %d, %d, %f, %f]\n",
        unpacked.First, unpacked.Second, unpacked.Third, unpacked.Fourth, unpacked.Fifth)
}

We're creating a struct that properly represents the binary format, then using binary.Read() to read our bytes into this struct. One thing to note is that golang's strings don't understand \e, so it must be converted to \x1b.

Output:

*@x~/go/src/stackoverflow.com/binunpack⦕ go run main.go
2018/10/07 17:39:16 [1073741917, 13798400, 0, 2417851639229258349412352.000000, 58518597001656773736660992.000000]
*@x~/go/src/stackoverflow.com/binunpack⦕
Will
  • 24,082
  • 14
  • 97
  • 108
  • 1
    Huh, that's cool. I've used encoding/binary before, but somehow up until now I never noticed that it handled structs :) – hobbs Oct 08 '18 at 01:28
  • Yeah, I just came across it the other day myself :) – Will Oct 08 '18 at 02:56