Python 十六进制数的往返前导0
我愿意加载一个包含32位十六进制数字的yaml文件,并保留前导0,这样数字的格式总是0xXXXXXXXX 我创建了一个自定义类并重新输入,以便可以在此表单中转储十六进制数:Python 十六进制数的往返前导0,python,yaml,ruamel.yaml,Python,Yaml,Ruamel.yaml,我愿意加载一个包含32位十六进制数字的yaml文件,并保留前导0,这样数字的格式总是0xXXXXXXXX 我创建了一个自定义类并重新输入,以便可以在此表单中转储十六进制数: class HexWInt(int): pass def represent_HexWInt(self, data): # type: (Any) -> Any return self.represent_scalar(u'tag:yaml.org,2002:int', '0x' +
class HexWInt(int):
pass
def represent_HexWInt(self, data):
# type: (Any) -> Any
return self.represent_scalar(u'tag:yaml.org,2002:int', '0x' + format(data, 'x').upper().zfill(8))
yaml.RoundTripRepresenter.add_representer(HexWInt, represent_HexWInt)
然而,我找不到一种合适的方法将这种格式应用于往返的十六进制数
事实上,以下是:
yamltext = "hexa: 0x0123ABCD"
code = yaml.round_trip_load(yamltext)
yaml.dump(code, sys.stdout, Dumper=yaml.RoundTripDumper)
显示
hexa: 0x123ABCD
我想在哪里展示这个
hexa: 0x0123ABCD
如何继续强制十六进制数字符合0xXXXXXXXX格式?有多种方法可以满足您的需要。如果不想影响解析器的正常行为,则应使用可选的
RoundTripConstructor
和RoundTripRepresenter
对RoundTripLoader
和RoundTripConstructor
进行子类化。但这需要注册所有构造函数和representer,而且非常冗长
如果您不想在以后的程序中加载其他带有前导零的十六进制标量整数的YAML文档,您可以添加一个新的构造函数,然后重新输入到RoundTripConstructor
和RoundTripRespresenter
最简单的部分是根据值和宽度获取格式。如果您使用的是格式,则不需要zfill()
或upper()
:
'0x{:0{}X}'.format(value, width)
代码不起作用的主要原因是因为代码从未构造过HexWInt
,因为RoundTripLoader
不知道它应该这样做。我也不会将宽度硬编码为8,而是从输入中派生出来(使用len()
),并保留它
import sys
import ruamel.yaml
class HexWInt(ruamel.yaml.scalarint.ScalarInt):
def __new__(cls, value, width):
x = ruamel.yaml.scalarint.ScalarInt.__new__(cls, value)
x._width = width # keep the original width
return x
def __isub__(self, a):
return HexWInt(self - a, self._width)
def alt_construct_yaml_int(constructor, node):
# check for 0x0 starting hex integers
value_s = ruamel.yaml.compat.to_str(constructor.construct_scalar(node))
if not value_s.startswith('0x0'):
return constructor.construct_yaml_int(node)
return HexWInt(int(value_s[2:], 16), len(value_s[2:]))
ruamel.yaml.constructor.RoundTripConstructor.add_constructor(
u'tag:yaml.org,2002:int', alt_construct_yaml_int)
def represent_hexw_int(representer, data):
return representer.represent_scalar(u'tag:yaml.org,2002:int',
'0x{:0{}X}'.format(data, data._width))
ruamel.yaml.representer.RoundTripRepresenter.add_representer(HexWInt, represent_hexw_int)
yaml_text = """\
hexa: 0x0123ABCD
hexb: 0x02AD
"""
yaml = ruamel.yaml.YAML()
data = yaml.load(yaml_text)
data['hexc'] = HexWInt(0xa1, 8)
data['hexb'] -= 3
yaml.dump(data, sys.stdout)
HexWInt
存储值和宽度alt\u construct\u yaml\u int
将所有内容传递给原始construct\u yaml\u int
,标量以0x0开始的情况除外。它是根据解析器完成的基于正则表达式的正常匹配,向add_constructor()
注册的。representer将值和宽度合并回一个字符串。上面的输出是:
hexa: 0x0123ABCD
hexb: 0x02AD
hexc: 0x000000A1
请注意,您不能执行以下操作:
data['hexb'] -= 3
因为ScalarInt
(具有方法\uuuu isub\uuu
)不知道宽度属性。要使上述方法起作用,您必须实现适当的方法,如ScalarInt
,就像HexWInt
上的方法一样。例如:
def __isub__(self, a):
return HexWInt(self - a, self._width)
上面的一个增强版本(它还保留整数中的,支持八进制和二进制整数)包含在ruamel.yaml>=0.14.7
中,有多种方法可以执行您想要的操作。如果不想影响解析器的正常行为,则应使用可选的RoundTripConstructor
和RoundTripRepresenter
对RoundTripLoader
和RoundTripConstructor
进行子类化。但这需要注册所有构造函数和representer,而且非常冗长
如果您不想在以后的程序中加载其他带有前导零的十六进制标量整数的YAML文档,您可以添加一个新的构造函数,然后重新输入到RoundTripConstructor
和RoundTripRespresenter
最简单的部分是根据值和宽度获取格式。如果您使用的是格式,则不需要zfill()
或upper()
:
'0x{:0{}X}'.format(value, width)
代码不起作用的主要原因是因为代码从未构造过HexWInt
,因为RoundTripLoader
不知道它应该这样做。我也不会将宽度硬编码为8,而是从输入中派生出来(使用len()
),并保留它
import sys
import ruamel.yaml
class HexWInt(ruamel.yaml.scalarint.ScalarInt):
def __new__(cls, value, width):
x = ruamel.yaml.scalarint.ScalarInt.__new__(cls, value)
x._width = width # keep the original width
return x
def __isub__(self, a):
return HexWInt(self - a, self._width)
def alt_construct_yaml_int(constructor, node):
# check for 0x0 starting hex integers
value_s = ruamel.yaml.compat.to_str(constructor.construct_scalar(node))
if not value_s.startswith('0x0'):
return constructor.construct_yaml_int(node)
return HexWInt(int(value_s[2:], 16), len(value_s[2:]))
ruamel.yaml.constructor.RoundTripConstructor.add_constructor(
u'tag:yaml.org,2002:int', alt_construct_yaml_int)
def represent_hexw_int(representer, data):
return representer.represent_scalar(u'tag:yaml.org,2002:int',
'0x{:0{}X}'.format(data, data._width))
ruamel.yaml.representer.RoundTripRepresenter.add_representer(HexWInt, represent_hexw_int)
yaml_text = """\
hexa: 0x0123ABCD
hexb: 0x02AD
"""
yaml = ruamel.yaml.YAML()
data = yaml.load(yaml_text)
data['hexc'] = HexWInt(0xa1, 8)
data['hexb'] -= 3
yaml.dump(data, sys.stdout)
HexWInt
存储值和宽度alt\u construct\u yaml\u int
将所有内容传递给原始construct\u yaml\u int
,标量以0x0开始的情况除外。它是根据解析器完成的基于正则表达式的正常匹配,向add_constructor()
注册的。representer将值和宽度合并回一个字符串。上面的输出是:
hexa: 0x0123ABCD
hexb: 0x02AD
hexc: 0x000000A1
请注意,您不能执行以下操作:
data['hexb'] -= 3
因为ScalarInt
(具有方法\uuuu isub\uuu
)不知道宽度属性。要使上述方法起作用,您必须实现适当的方法,如ScalarInt
,就像HexWInt
上的方法一样。例如:
def __isub__(self, a):
return HexWInt(self - a, self._width)
上面的一个增强版本(它还保留了整数中的\uu
,并支持八进制和二进制整数)包含在ruamel.yaml>=0.14.7
中,太好了,谢谢!来回跟踪十进制数字的0也有意义吗?例如,它将有助于存储版本号。@noname120我不知道十进制数字是什么意思。对于任何解释为整数(十六进制、八进制、十进制、二进制)的标量,尾随的零确定不同的值,该值(以及零)将保留。如果你说的标量是浮点数,那么仅仅做零是不够的,因为整个解释(科学记数法、尾数、符号)目前已经丢失,而且大多数编程语言在浮点数的表示上都有错误。即使是整数(在0.14.7中),符号也会被删除。实数小数需要一个带标记的类型才能精确往返。好的,谢谢你的解释。对于一个具体的示例,使用往返,将变成固件:3.6
。不过,这不是什么大麻烦。太好了,谢谢!来回跟踪十进制数字的0也有意义吗?例如,它将有助于存储版本号。@noname120我不知道十进制数字是什么意思。对于任何sc