Golang中如何将JSON编码的字节数组转换为十六进制字符串而非Base64

Golang中如何将JSON编码的字节数组转换为十六进制字符串而非Base64 我正在尝试将一个 interface{} 对象序列化为 JSON 格式并以更友好的视图打印出来,除了字节数组部分,其他都基本正常。 我知道默认情况下:

数组和切片值编码为 JSON 数组,但 []byte 编码为 base64 编码的字符串,而 nil 切片编码为 null JSON 值。

但我希望将这些字节数组以十六进制字符串的形式打印,而不是 base64(因为对于区块链地址/交易来说,十六进制更常见)。 我无法为此预定义结构体并使用自定义的 MarshalJson 函数,因为这个对象实际上不是我初始化的,而是从另一种数据格式(CBOR)解码而来,因此其结构可能会变化。 有人有解决这个问题的办法吗? 当我使用 fmt.Printf("%x\n", data) 以十六进制打印数据时:

map[0:[[9c37cb5294abce709bfa57bdcab039d75e212a503bc48d5b45e6ff4eb6272759 1] [77df5bd720b6fb8699762fea21bdbc8193a61b770a59443266383ba01a6b8900 1]] 1:[[00177a56a4202e7edd0f394bb850b9dfe072e205f947d7ccb3f8dcb476e10a200512c808028cbbf6758978026a2d8ed307c65de78625d7596c 64] [0067fa035e20501b0507356e7e75278f9f30dad9a8fe3826798b3ee0b0e10a200512c808028cbbf6758978026a2d8ed307c65de78625d7596c a]] 2:64]

更多关于Golang中如何将JSON编码的字节数组转换为十六进制字符串而非Base64的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

说得好,我显然忽略了“可能有所不同”这一部分。

更多关于Golang中如何将JSON编码的字节数组转换为十六进制字符串而非Base64的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


也许我漏掉了什么,但这对于原帖作者来说并不简单,因为:

marshal an interface{} object…it’s structure may vary

必须使用反射来遍历和复制原始对象,将字节数组替换为定义了 MarshalJSON 方法的用户自定义类型,但可能没有更好的方法了。一个更不优雅的替代方案是对 JSON 进行后处理。

你好 @Yenle9

你可以编写一个自定义的编组器,使用 encoding/hex 来处理字节切片到十六进制的转换。我在 StackOverflow 上找到了一个例子:如何在将 go 编码为 json 时强制将 [8]byte 编码为十六进制 - Stack Overflow

在Golang中,你可以通过自定义JSON编码器来实现将字节数组编码为十六进制字符串。这里的关键是使用json.Marshaler接口,但考虑到你的数据是动态的,需要递归处理。以下是一个解决方案:

package main

import (
    "encoding/hex"
    "encoding/json"
    "fmt"
    "reflect"
)

// HexMarshaler 递归地将字节切片转换为十六进制字符串
type HexMarshaler struct{}

func (h HexMarshaler) MarshalJSON() ([]byte, error) {
    return json.Marshal(h.convertToHex(reflect.ValueOf(h)))
}

func (h HexMarshaler) convertToHex(v reflect.Value) interface{} {
    switch v.Kind() {
    case reflect.Slice:
        if v.Type().Elem().Kind() == reflect.Uint8 {
            // 字节切片转换为十六进制字符串
            return hex.EncodeToString(v.Bytes())
        }
        // 递归处理切片元素
        result := make([]interface{}, v.Len())
        for i := 0; i < v.Len(); i++ {
            result[i] = h.convertToHex(v.Index(i))
        }
        return result
    case reflect.Map:
        // 递归处理map
        result := make(map[string]interface{})
        iter := v.MapRange()
        for iter.Next() {
            key := fmt.Sprintf("%v", iter.Key().Interface())
            result[key] = h.convertToHex(iter.Value())
        }
        return result
    case reflect.Interface:
        // 处理interface{}类型
        if v.IsNil() {
            return nil
        }
        return h.convertToHex(v.Elem())
    default:
        return v.Interface()
    }
}

func main() {
    // 示例数据
    data := map[string]interface{}{
        "address": []byte{0x9c, 0x37, 0xcb, 0x52, 0x94, 0xab, 0xce, 0x70},
        "nested": map[string]interface{}{
            "tx": []byte{0x77, 0xdf, 0x5b, 0xd7, 0x20, 0xb6, 0xfb, 0x86},
        },
        "list": []interface{}{
            []byte{0x00, 0x17, 0x7a, 0x56},
            "regular string",
            42,
        },
    }

    // 使用自定义编码器
    marshaled, err := json.Marshal(HexMarshaler{data})
    if err != nil {
        panic(err)
    }

    fmt.Println(string(marshaled))
}

对于你的具体数据结构,这里是一个更直接的实现:

func convertToHex(data interface{}) interface{} {
    switch v := data.(type) {
    case []byte:
        return hex.EncodeToString(v)
    case []interface{}:
        result := make([]interface{}, len(v))
        for i, item := range v {
            result[i] = convertToHex(item)
        }
        return result
    case map[string]interface{}:
        result := make(map[string]interface{})
        for key, val := range v {
            result[key] = convertToHex(val)
        }
        return result
    case map[interface{}]interface{}:
        result := make(map[string]interface{})
        for key, val := range v {
            result[fmt.Sprintf("%v", key)] = convertToHex(val)
        }
        return result
    default:
        return v
    }
}

// 使用示例
func main() {
    // 假设这是你的CBOR解码结果
    cborData := map[interface{}]interface{}{
        0: []interface{}{
            []byte{0x9c, 0x37, 0xcb, 0x52, 0x94, 0xab, 0xce, 0x70},
            1,
        },
        1: []interface{}{
            []byte{0x00, 0x17, 0x7a, 0x56, 0xa4, 0x20, 0x2e, 0x7e},
            64,
        },
    }

    // 转换为十六进制格式
    hexData := convertToHex(cborData)
    
    // 编码为JSON
    jsonBytes, err := json.MarshalIndent(hexData, "", "  ")
    if err != nil {
        panic(err)
    }
    
    fmt.Println(string(jsonBytes))
}

输出结果中的字节数组会被转换为十六进制字符串:

{
  "0": [
    "9c37cb5294abce70",
    1
  ],
  "1": [
    "00177a56a4202e7e",
    64
  ]
}

这种方法通过递归遍历数据结构,将遇到的每个[]byte都转换为十六进制字符串,同时保持其他数据类型不变。这样你就可以在不预定义结构体的情况下,将任意包含字节数组的数据结构编码为十六进制格式的JSON。

回到顶部