我有一个简单的以下程序:
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
但是,当我尝试使用以下 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 端的代码没有任何影响(但是对于尝试做类似事情的其他人来说,Go 端解决方案仍然是受欢迎的)。
最佳答案
您可以在 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的实际输出是不正确的,如果你使用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.py
的原因
好吧)。
这对于像 "True"
和 "2019-02-08' 这样的字符串也有同样的作用,它们也会被引用(按顺序)
不要将它们与 bool 值或日期“混淆”)。
这是一个相当昂贵的计算过程,当然还有其他方法 确定是否需要报价。
在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 和 Python 关于整数的大小。但在 Go 中限制为 64 位。所以在上面的 ParseInt 返回一个错误并且 go 认为 字符串不需要引号。 (我将此报告为 bug在 go-yaml 中 库)。
出发 Marshall
函数似乎没有像您一样强制引用的标志
在 ruamel.yaml`` 中设置 yaml.default_style = '"'` 即可。
关于python - 如何使用 Go 和 Python 处理 YAML 中的十六进制值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54584832/