Python 如何让construct.greedRange返回一个字节?
好吧,假设我让它完全按照预期工作: 从enum导入IntEnum 从contstruct导入* 夏令营: 开始=0xAB 停止=0xBC ESC=0xCD MAPPING=MappingByte,{x:x+1表示字符中的x} 滑动=格里迪范围 选择 聚焦均衡 “x”, ConstChar.ESC,字节, 重命名贴图“x” , 字节 例如: >>>缓冲区=字节[0x00,0xAB,0xBC,0xCD,0xFF] >>>滑动缓冲区 b'\x00\xcd\xac\xcd\xbd\xcd\xce\xff' 以及: >>>从运算符导入eq >>>allmapeq,SLIP.parseSLIP.buildbuffer,buffer 符合事实的 现在我需要将编码/解码包装到另一个结构中: 协议=聚焦均衡 "讯息",, ConstChar.START,字节, 重命名纸条,“消息”, ConstChar.STOP,字节 构建完全按照预期工作: >>>PROTOCOL.buildbuffer b'\xab\x00\xcd\xac\xcd\xbd\xcd\xce\xff\xbc' 但是,解析时,GreedyRange消耗的字节太多: >>>协议.parseb'\xab\x00\xcd\xac\xcd\xbd\xcd\xce\xff\xbc' construct.core.StreamError:流读取少于指定量,应为1,找到0Python 如何让construct.greedRange返回一个字节?,python,struct,enums,construct,Python,Struct,Enums,Construct,好吧,假设我让它完全按照预期工作: 从enum导入IntEnum 从contstruct导入* 夏令营: 开始=0xAB 停止=0xBC ESC=0xCD MAPPING=MappingByte,{x:x+1表示字符中的x} 滑动=格里迪范围 选择 聚焦均衡 “x”, ConstChar.ESC,字节, 重命名贴图“x” , 字节 例如: >>>缓冲区=字节[0x00,0xAB,0xBC,0xCD,0xFF] >>>滑动缓冲区 b'\x00\xcd\xac\xcd\xbd\xcd\xce\xff
如何让GreedyRange返回一个字节?在您的情况下,您可以简单地重新排列协议字段并在末尾添加SLIP
PROTOCOL = FocusedSeq(
'message',
Const(Char.START, Byte),
Const(Char.STOP, Byte),
Renamed(SLIP, 'message')
)
这样,GreedyRange将不会使用导致流分析错误的所有字节:construct.core.StreamError:流读取少于指定数量,应为1,找到0
以下是一个修改后的示例:
from construct import Byte, Const, FocusedSeq, GreedyRange, Mapping, Renamed, Select
from enum import IntEnum
class Char(IntEnum):
START = 0xAB
STOP = 0xBC
ESC = 0xCD
MAPPING = Mapping(Byte, {x: x+1 for x in Char})
SLIP = GreedyRange(
Select(
FocusedSeq(
'x',
Const(Char.ESC, Byte),
Renamed(MAPPING, 'x')
),
Byte
)
)
buffer = bytes([0x00, 0xAB, 0xBC, 0xCD, 0xFF])
slip_build = SLIP.build(buffer)
assert slip_build == b'\x00\xcd\xac\xcd\xbd\xcd\xce\xff'
slip_parsed = SLIP.parse(b'\x00\xcd\xac\xcd\xbd\xcd\xce\xff')
PROTOCOL = FocusedSeq(
'message',
Const(Char.START, Byte),
Const(Char.STOP, Byte),
Renamed(SLIP, 'message')
)
protocol_build = PROTOCOL.build(buffer)
assert protocol_build == b'\xab\xbc\x00\xcd\xac\xcd\xbd\xcd\xce\xff'
protocol_parsed = PROTOCOL.parse(protocol_build)
assert protocol_parsed == slip_parsed
解决方案是NullTerminated…,term=STOP,它在内部缓冲底层流,并在必要时返回
PROTOCOL = FocusedSeq(
'message'
Const(Char.START, Byte),
message=NullTerminated(
# NOTE build consumes entire stream and appends STOP
# NOTE parse consumes steam until STOP and passes buffer to GreedyRange
GreedyRange(
Select(
FocusedSeq(
'x',
Const(Char.ESC, Byte),
x=MAPPING # NOTE intentionally raises MappingError
),
Byte # NOTE fallback for MappingError
)
),
term=Byte.build(Char.STOP)
)
)
另一种方法是使用修改字节序列 下面是另一个代码示例:
from construct import Byte, Const, FocusedSeq, GreedyRange, \
If, Mapping, Renamed, Select, this, Adapter
from enum import IntEnum
class Char(IntEnum):
START = 0xAB
STOP = 0xBC
ESC = 0xCD
MAPPING = Mapping(Byte, {x: x+1 for x in Char})
SLIP = GreedyRange(
Select(
FocusedSeq(
'x',
Const(Char.ESC, Byte),
Renamed(MAPPING, 'x')
),
Byte
)
)
buffer = bytes([0x00, 0xAB, 0xBC, 0xCD, 0xFF])
slip_build = SLIP.build(buffer)
assert slip_build == b'\x00\xcd\xac\xcd\xbd\xcd\xce\xff'
slip_parsed = SLIP.parse(b'\x00\xcd\xac\xcd\xbd\xcd\xce\xff')
class ProtocolAdapter(Adapter):
def _decode(self, obj, context, path):
# remove first and last bite
obj.pop(0)
obj.pop(-1)
return obj
def _encode(self, obj, context, path):
return obj
PROTOCOL = FocusedSeq(
"message",
If(this._building == True, Const(Char.START, Byte)),
"message" / SLIP,
If(this._building == True, Const(Char.STOP, Byte))
)
ADAPTED_PROTOCOL = ProtocolAdapter(PROTOCOL)
protocol_build = ADAPTED_PROTOCOL.build(buffer)
assert protocol_build == b'\xab\x00\xcd\xac\xcd\xbd\xcd\xce\xff\xbc'
protocol_parsed = ADAPTED_PROTOCOL.parse(protocol_build)
assert protocol_parsed == slip_parsed
不幸的是,这是不对的;生成的缓冲区必须以BC结尾,而不是第二个字符