fmt.Sscanf неправильно читает шестнадцатеричное - PullRequest
1 голос
/ 14 января 2020

У меня проблемы с чтением значения, которое я сериализовал в шестнадцатеричный формат. Следующий код выдает значение 0x14, когда я форматирую целое число. Однако, когда я пытаюсь прочитать это значение обратно из строки, я получаю неверные результаты. Может ли кто-нибудь помочь мне понять, что я делаю неправильно?

У меня есть существующие текстовые файлы, которые я анализирую с несколькими строками, включающими этот формат, поэтому сериализация в другой формат не будет жизнеспособной решение. Мне нужно работать с этим указанным c форматом.

Согласно go документам, это должно работать: https://golang.org/pkg/fmt/

Глаголы ведут себя аналогично принтф. Например,% x будет сканировать целое число как шестнадцатеричное число, а% v будет сканировать формат представления по умолчанию для значения. Глаголы Printf% p и% T и флаги # и + не реализованы. Для значений с плавающей запятой и комплексных значений все действительные глаголы форматирования (% b% e% E% f% F% g% G% x% X и% v) эквивалентны и принимают как десятичные, так и шестнадцатеричные обозначения (например, «2.3 e + 7 "," 0x4.5p-8 ") и подчеркивание ди git (например," 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
}

Ответы [ 2 ]

5 голосов
/ 14 января 2020

Глагол %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 Детская площадка . Это обеспечивает гибкость в том, что ввод может быть указан в нескольких базах, база будет обнаружена по префиксу («% v будет сканировать формат представления по умолчанию для значения» ), например, 0x для гекса, 0 для восьмеричного, 0b для двоичного.

Вы также можете использовать strconv.ParseInt(), где вы можете указать base == 0, в этом случае «основание подразумевается префиксом строки: основание 2 для« 0b », основание 8 для« 0 »или« 0o », основание 16 для« 0x »и основание 10 в противном случае» .

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

Попробуйте это на Go Детская площадка .

5 голосов
/ 14 января 2020

Обратите внимание на это предложение в документах:

Глаголы Printf% p и% T и флаги # и + не реализованы.

Итак:

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) 
...