fmt.Sscanf 无法正确读取十六进制

fmt.Sscanf doesn't properly read hexadecimal

我在读回已序列化为十六进制格式的值时遇到问题。当我格式化一个整数时,下面的代码产生一个值 0x14。但是,当我尝试从字符串中读回该值时,我得到了无效结果。谁能帮我弄清楚我做错了什么?

我有预先存在的文本文件,我正在用包含这种格式的多行进行解析,因此序列化为不同的格式将不是一个可行的解决方案。我需要使用这种特定格式。

根据 go 文档,这应该有效:https://golang.org/pkg/fmt/

The verbs behave analogously to those of Printf. For example, %x will scan an integer as a hexadecimal number, and %v will scan the default representation format for the value. The Printf verbs %p and %T and the flags # and + are not implemented. For floating-point and complex values, all valid formatting verbs (%b %e %E %f %F %g %G %x %X and %v) are equivalent and accept both decimal and hexadecimal notation (for example: "2.3e+7", "0x4.5p-8") and digit-separating underscores (for example: "3.14159_26535_89793").

package main

import (
    "fmt"
)

func main() {
    encode := 20
    fmt.Println(fmt.Sprintf("%#x", encode)) // 0x14

    var decode int
    numRead, err := fmt.Sscanf("0x14", "%#x", &decode)
    fmt.Println(decode, numRead, err) // 0 1 bad verb '%#' for integer

    numRead, err = fmt.Sscanf("0x14", "%x", &decode)
    fmt.Println(decode, numRead, err) // 0 1 nil
}

注意文档中的这句话:

The Printf verbs %p and %T and the flags # and + are not implemented.

所以:

var decode int
numRead, err := fmt.Sscanf("0x14", "0x%x", &decode)
fmt.Println(decode, numRead, err) 

numRead, err = fmt.Sscanf("14", "%x", &decode)
fmt.Println(decode, numRead, err) 

%x 动词将扫描十六进制整数,但不扫描 0x 前缀。您可以将该前缀添加到格式字符串中:

var decode int
numRead, err := fmt.Sscanf("0x14", "0x%x", &decode)
fmt.Println(decode, numRead, err) 

这将正确扫描 0x14 输入为 20 的十进制整数值(在 Go Playground 上尝试):

20 1 <nil>

另一种选择是使用 %v 动词来处理前缀并检测它是一个十六进制数:

var decode int
numRead, err := fmt.Sscanf("0x14", "%v", &decode)
fmt.Println(decode, numRead, err) // Outputs: 20 <nil>

这输出相同。在 Go Playground 上试试这个。这具有灵活性,可以在多个碱基中指定输入,碱基将从前缀中检测(“%v 将扫描值的默认表示格式”),例如 0x 表示六进制,0 表示八进制,0b 表示二进制。

您也可以使用 strconv.ParseInt(),其中您可以指定 base == 0,在这种情况下 "the base is implied by the string's prefix: base 2 for "0b",以 8 为基数表示“0”或“0o” ","0x" 以 16 为底,否则以 10 为底"

decode, err := strconv.ParseInt("0x14", 0, 64)
fmt.Println(decode, err)

Go Playground 上试试这个。