Как работать со значениями Hex в YAML, используя Go и Python? - PullRequest
0 голосов
/ 08 февраля 2019

У меня есть эта простая следующая программа:

package main

import (
    "fmt"

    yaml "gopkg.in/yaml.v2"
)

type Test struct {
    SomeStringWithQuotes string `yaml:"someStringWithQuotes"`
    SomeString           string `yaml:"someString"`
    SomeHexValue         string `yaml:"someHexValue"`
}

func main() {
    t := Test{
        SomeStringWithQuotes: "\"Hello World\"",
        SomeString:           "Hello World",
        SomeHexValue:         "0xDef9C64256DeE61ebf5B212238df11C7E532e3B7",
    }
    yamlBytes, _ := yaml.Marshal(t)
    fmt.Print(string(yamlBytes))
}

Это печатает следующее и очевидно демонстрирует, что Go принимает решение о том, когда заключать в кавычки строку или нет:

someStringWithQuotes: '"Hello World"'
someString: Hello World
someHexValue: 0xDef9C64256DeE61ebf5B212238df11C7E532e3B7

Однако,когда я пытаюсь прочитать этот YAML, используя следующий скрипт Python:

import yaml

yaml_str = """
someStringWithQuotes: '"Hello World"'
someString: Hello World
someHexValue: 0xDef9C64256DeE61ebf5B212238df11C7E532e3B7
"""

print(yaml.load(yaml_str))

Он анализирует значение Hex как целое число.Если я теперь верну сериализацию обратно в YAML, используя этот код:

import yaml
import sys

yaml_str = """
someStringWithQuotes: '"Hello World"'
someString: Hello World
someHexValue: 0xDef9C64256DeE61ebf5B212238df11C7E532e3B7
"""

print(yaml.dump(yaml.load(yaml_str)))

, я получу:

someHexValue: 1272966107484048169783147972546098614451903325111
someString: Hello World
someStringWithQuotes: '"Hello World"'

Как лучше всего убедиться, что формат Hex сохранен?К сожалению, я лично не имею никакого влияния на код на стороне Go (но решение на стороне Go все еще приветствуется для других людей, которые пытаются делать подобные вещи).

Ответы [ 2 ]

0 голосов
/ 08 февраля 2019

Вы можете загрузить и выгрузить этот вывод в Python, сохранив шестнадцатеричное значение, используя ruamel.yaml (отказ от ответственности: я являюсь автором этого пакета Python):

import sys
import ruamel.yaml

yaml_str = """\
someHexValue: 0xDef9C64256DeE61ebf5B212238df11C7E532e3B7
someString: Hello World
someStringWithQuotes: '"Hello World"'
"""

yaml = ruamel.yaml.YAML()
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)

, что дает:

someHexValue: 0xDEF9C64256DEE61EBF5B212238DF11C7E532E3B7
someString: Hello World
someStringWithQuotes: '"Hello World"'

Фактический вывод команды go неправильный, если вы должны вывести строку "0xDef9C64256DeE61ebf5B212238df11C7E532e3B7" с помощью Python, то вы увидите, что она выводит эту строку с кавычками (здесь я использую ruamel.yaml, ноэто работает так же для PyYAML):

import sys
import ruamel.yaml

data = dict(someHexValue="0xDef9C64256DeE61ebf5B212238df11C7E532e3B7")

yaml = ruamel.yaml.YAML()
yaml.dump(data, sys.stdout)

, что дает:

someHexValue: '0xDef9C64256DeE61ebf5B212238df11C7E532e3B7'

То, что эта строка нуждается в кавычках, определяется представлением строки "plain" (то есть без кавычек) изатем попытаться разрешить его, чтобы убедиться, что оргинальный тип (строка) возвращается.Это не тот случай, так как он является целым числом, и представительная часть процесса выгрузки решает, что кавычки необходимы.(Если вы когда-нибудь посмотрите на код загрузки и выгрузки и задаетесь вопросом, почему распознаватель используется обоими: по этой причине дамперу также необходим доступ к resolver.py).

Это работает одинаководля строки типа "True" и «2019-02-08», которые также заключаются в кавычки (чтобы не «путать» их с логическим значением или датой).

Это довольно дорогой вычислительный процесси, конечно, есть и другие способы определить, нужны ли кавычки.

На ходу это работает аналогичным образом, но в соответствующем коде есть ошибка в resolve.go:

        intv, err := strconv.ParseInt(plain, 0, 64)
        if err == nil {
            if intv == int64(int(intv)) {
                return yaml_INT_TAG, int(intv)
            } else {
                return yaml_INT_TAG, intv
            }
        }

Из документации для ParseInt:

Если base == 0, основание подразумевается префиксом строки: base 16 для "0x", base 8 для "0",и основание 10. в противном случае.

Проблема, конечно, заключается в том, что в YAML и Python нет ограничений на размер целого числа. Но в действительности они ограничены 64 битами.ParseInt возвращает ошибку и думает, что строка не нужнапроцитировать.(Я сообщил об этом как ошибка в библиотеке go-yaml).

Функция go Marshall не имеет флага для принудительного цитированиякак вы можете сделать с настройкой yaml.default_style = '"'` in ruamel.yaml``.

0 голосов
/ 08 февраля 2019

Go интерпретирует эту шестнадцатеричную строку как число.

someHexValue: 0xDef9C64256DeE61ebf5B212238df11C7E532e3B7

Если это yaml, который он производит, то python будет прав, считая его числом.

Помощь группы для этогов Python это преобразовать его обратно в гекс, используя

hex(1272966107484048169783147972546098614451903325111)

Вот спецификация yaml , которая обрабатывает этот гекс как число

...