如何使用Go和Python处理YAML中的十六进制值?

2024-10-01 05:00:45 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个简单的程序:

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决定何时引用字符串:

^{pr2}$

但是,当我尝试使用以下Python脚本阅读此YAML时:

import yaml

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

print(yaml.load(yaml_str))

它将十六进制值解析为整数。如果我现在使用以下代码序列化回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"'

如何才能最好地确保保留十六进制格式?不幸的是,我个人对代码没有任何影响(但是对于尝试做类似事情的其他人来说,Go-side解决方案仍然是受欢迎的)。在


Tags: testimportyamlhelloworldstringmainstr
2条回答

您可以在使用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)

它给出了:

^{pr2}$

go的实际输出是不正确的,如果使用Python输出字符串"0xDef9C64256DeE61ebf5B212238df11C7E532e3B7",那么您将看到它输出 带引号的字符串(我在这里使用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.pyas的原因 好吧)。在

这对于"True"和“2019-02-08”这样的字符串也是一样的,它们也被引用(按顺序 不要用布尔值或日期来“混淆”它们)。在

这是一个相当昂贵的计算过程,当然还有其他方法 决定是否需要引用。在

在go中,这是以相同的方式工作的,但是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的文档:

If base == 0, the base is implied by the string's prefix: base 16 for "0x", base 8 for "0", and base 10 otherwise.

问题当然是在YAML和in中没有限制 一个整数大小的Python。但在围棋比赛中被限制在64人以内 位。所以在上面的ParseInt返回一个错误,go认为 字符串不需要引用。(我以 bug即兴表演 图书馆)。在

^{} 函数似乎没有一个可以强制引用的标志 执行设置yaml.default_style = '"'` in拉梅尔亚姆勒``. 在

Go将那个十六进制字符串解释为一个数字。在

someHexValue: 0xDef9C64256DeE61ebf5B212238df11C7E532e3B7

如果这是它生成的yaml,那么python将其视为数字是正确的。在

python中的一个创可贴是使用

^{pr2}$

{这是一个十六进制数

相关问题 更多 >