十六进制数的往返前导 0
Roundtrip leading 0s of hexadecimal numbers
我愿意加载一个包含 32 位十六进制数字的 yaml 文件,并保留前导 0,以便数字始终采用 0xXXXXXXXX 形式。
我创建了一个自定义 class 和表示器,以便可以以这种形式转储十六进制数:
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 格式?
有多种方法可以满足您的需求。如果您不想影响解析器的正常行为,您应该将 RoundTripLoader
和 RoundTripConstructor
子类化为 RoundTripConstructor
和 RoundTripRepresenter
。但这需要注册所有构造函数和表示器,而且非常冗长。
如果您不关心稍后在您的程序中使用带有前导零 原始功能的十六进制标量整数加载其他 YAML 文档,您可以只向 RoundTripConstructor
和 RoundTripRepresenter
.
添加一个新的构造函数和表示器
最简单的部分是根据值和宽度获取格式。如果您仍然使用 format
,则不需要 zfill()
或 upper()
:
'0x{:0{}X}'.format(value, width)
您的代码不起作用的主要原因是因为您的代码从不构造 HexWInt
,因为 RoundTripLoader
不知道它应该这样做。我也不会将宽度硬编码为八,而是从输入中导出它(使用 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_construct_yaml_int
将所有内容传递给原始 construct_yaml_int
,标量以 0x0
开头的情况除外。它根据解析器完成的基于正常正则表达式的匹配注册到 add_constructor()
。代表将值和宽度组合回一个字符串。上面的输出是:
hexa: 0x0123ABCD
hexb: 0x02AD
hexc: 0x000000A1
请注意,您不能执行以下操作:
data['hexb'] -= 3
as ScalarInt
(确实有方法 __isub__
)不知道 width 属性。要使上述工作正常,您必须实现适当的方法,例如 ScalarInt
和 HexWInt
上的方法。例如:
def __isub__(self, a):
return HexWInt(self - a, self._width)
ruamel.yaml>=0.14.7
合并了上述的增强版本(它也保留 _
整数并支持八进制和二进制整数)
我愿意加载一个包含 32 位十六进制数字的 yaml 文件,并保留前导 0,以便数字始终采用 0xXXXXXXXX 形式。
我创建了一个自定义 class 和表示器,以便可以以这种形式转储十六进制数:
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 格式?
有多种方法可以满足您的需求。如果您不想影响解析器的正常行为,您应该将 RoundTripLoader
和 RoundTripConstructor
子类化为 RoundTripConstructor
和 RoundTripRepresenter
。但这需要注册所有构造函数和表示器,而且非常冗长。
如果您不关心稍后在您的程序中使用带有前导零 原始功能的十六进制标量整数加载其他 YAML 文档,您可以只向 RoundTripConstructor
和 RoundTripRepresenter
.
最简单的部分是根据值和宽度获取格式。如果您仍然使用 format
,则不需要 zfill()
或 upper()
:
'0x{:0{}X}'.format(value, width)
您的代码不起作用的主要原因是因为您的代码从不构造 HexWInt
,因为 RoundTripLoader
不知道它应该这样做。我也不会将宽度硬编码为八,而是从输入中导出它(使用 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_construct_yaml_int
将所有内容传递给原始 construct_yaml_int
,标量以 0x0
开头的情况除外。它根据解析器完成的基于正常正则表达式的匹配注册到 add_constructor()
。代表将值和宽度组合回一个字符串。上面的输出是:
hexa: 0x0123ABCD
hexb: 0x02AD
hexc: 0x000000A1
请注意,您不能执行以下操作:
data['hexb'] -= 3
as ScalarInt
(确实有方法 __isub__
)不知道 width 属性。要使上述工作正常,您必须实现适当的方法,例如 ScalarInt
和 HexWInt
上的方法。例如:
def __isub__(self, a):
return HexWInt(self - a, self._width)
ruamel.yaml>=0.14.7
_
整数并支持八进制和二进制整数)