5
\$\begingroup\$

I'm pretty sure this can be written as a couple of lines, but I'm unable to come up with a better solution.

package main
import (
 "fmt"
 "math/big"
)
func colonedSerial(i *big.Int) string {
 hex := fmt.Sprintf("%x", i)
 if len(hex)%2 == 1 {
 hex = "0" + hex
 }
 numberOfColons := len(hex)/2 - 1
 colonedHex := make([]byte, len(hex)+numberOfColons)
 for i, j := 0, 0; i < len(hex)-1; i, j = i+1, j+1 {
 colonedHex[j] = hex[i]
 if i%2 == 1 {
 j++
 colonedHex[j] = []byte(":")[0]
 }
 }
 // we skipped the last one to avoid the colon at the end
 colonedHex[len(colonedHex)-1] = hex[len(hex)-1]
 return string(colonedHex)
}
func main() {
 fmt.Println(colonedSerial(big.NewInt(1234)))
 // "04:d2"
 fmt.Println(colonedSerial(big.NewInt(123456)))
 // "01:e2:40"
 fmt.Println(colonedSerial(big.NewInt(1234567891011121314)))
 // "11:22:10:f4:b2:d2:30:a2"
}

Also the []byte(":")[0] is very ugly. Is there a better way to do that? (I did not wanted to write the ASCII value of colon (58) as it would be a magic number).

Go Playground version: https://play.golang.org/p/GTxajcr3NY

200_success
146k22 gold badges190 silver badges479 bronze badges
asked Jun 13, 2017 at 21:18
\$\endgroup\$
0

2 Answers 2

4
\$\begingroup\$

In Go, we usually expect reasonable performance and brevity. For example,

package main
import (
 "encoding/hex"
 "fmt"
 "math/big"
)
func formatSerial(serial *big.Int) string {
 b := serial.Bytes()
 buf := make([]byte, 0, 3*len(b))
 x := buf[1*len(b) : 3*len(b)]
 hex.Encode(x, b)
 for i := 0; i < len(x); i += 2 {
 buf = append(buf, x[i], x[i+1], ':')
 }
 return string(buf[:len(buf)-1])
}
func main() {
 fmt.Println(formatSerial(big.NewInt(1234)))
 // "04:d2"
 fmt.Println(formatSerial(big.NewInt(123456)))
 // "01:e2:40"
 fmt.Println(formatSerial(big.NewInt(1234567891011121314)))
 // "11:22:10:f4:b2:d2:30:a2"
}

Output:

04:d2
01:e2:40
11:22:10:f4:b2:d2:30:a2

Benchmark: serial := big.NewInt(1234567891011121314):

BenchmarkPeterSO 3000000 552 ns/op 72 B/op 3 allocs/op
BenchmarkKissgyorgy 500000 2545 ns/op 120 B/op 7 allocs/op
Benchmark200Success 30000 40675 ns/op 40675 B/op 35 allocs/op
answered Jun 13, 2017 at 23:21
\$\endgroup\$
3
  • 1
    \$\begingroup\$ oh wow. I didn't wanted to use append to avoid multiple allocations, but the cap trick is nice! but how is yours so much faster than mine? what are those allocations in my version? I explicitly wanted to avoid those, that's whhy I made a byte slice and not string concatenation \$\endgroup\$ Commented Jun 14, 2017 at 6:22
  • 2
    \$\begingroup\$ @kissgyorgy: When you write fmt.Sprintf("%x", i), it interprets the format string and, by reflection, inspects the format variables at run time. Read the Go code for src/fmt/format.go and src/fmt/print.go. For example, try replacing fmt.Sprintf("%x", i) with i.Text(16). My code is compile-time code that does close to the minimum. \$\endgroup\$ Commented Jun 14, 2017 at 18:14
  • 1
    \$\begingroup\$ Ok I just understood your version now. You use only one array, store the hex elements from the middle and store the final from the start reusing the full array at the end. I like it very much, thanks! \$\endgroup\$ Commented Jun 14, 2017 at 21:54
2
\$\begingroup\$

Since the task mainly involves inserting a colon after every two hex digits, I would treat it as a search-and-replace operation, using a regular expression.

import (
 "fmt"
 "math/big"
 "regexp"
 "strings"
)
func colonedSerial(i *big.Int) string {
 re := regexp.MustCompile("..")
 hex := fmt.Sprintf("%x", i)
 if len(hex)%2 == 1 {
 hex = "0" + hex
 }
 return strings.TrimRight(re.ReplaceAllString(hex, "0ドル:"), ":")
}
answered Jun 13, 2017 at 22:34
\$\endgroup\$
1
  • \$\begingroup\$ This is actually really nice! \$\endgroup\$ Commented Jun 14, 2017 at 6:27

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.