gpt4 book ai didi

python - 八位字节(字节)填充和取消填充,即用两个或 v.v 替换一个字节

转载 作者:太空宇宙 更新时间:2023-11-03 13:48:56 26 4
gpt4 key购买 nike

我正在使用 socket.recv() 通过套接字(蓝牙)从设备接收二进制数据。

我考虑过在列表或字节数组中进行缓冲,直到收到足够的数据进行解码和操作。也就是说,直到我收到开始标志和停止标志(字节)。

但是,设备正在应用“八位字节填充”。也就是说,以下两个字节的每次出现都应替换为单个字节,如下所示:

dic = { '\xFE\xDC' : '\xFC' , '\xFE\xDD' : '\xFD' , '\xFE\xDE' : '\xFE'}

此外,在发送数据时,应该应用反向。例如,一个字节 0xFC -> 产生两个字节 0xFE、0xDC。

真正发生的是,当填充(发送数据)时,如果检测到 0xFC、0xFD、0xFE 之一,则在字节之前添加 0xFE,该字节本身是异或 0x20。在取消填充(接收数据)时,0XFE 被丢弃,随后的字节被异或 0x20。

说我是 Python 的新手一点都不为过。我昨天开始编码,启动并运行了一个界面。然而,这有点棘手。

我知道我可以将数据放入字符串中并进行替换。但是把二进制数据打包成字符串,替换然后解包解码好像效率有点低。

我还可以查看传入数据并在看到 0xFE 标志时采取行动。如果有一种方法可以填充/取消填充列表、字节数组或其他任何东西,那就太好了。

替换列表或 bytearray 中的单个字节似乎并不难,但是用两个替换一个或其他方式......?

非常感谢任何帮助。

(顺便说一句,这是 Python 2.7。)

最佳答案

概览

您需要包装字节流并转义特定值。此外,还需要另一种方法:取消转义控制代码并获取原始有效负载。您正在使用套接字。套接字命令使用字符串参数。在 Python 中,每个字符串基本上都是 char* 数组的包装器。

朴素的方法

它是一个字符串,我们想用其他值替换特定值。那么实现这一目标的最简单方法是什么?

def unstuff(self, s):
return s.replace('\xFE\xDC', '\xFC').replace('\xFE\xDD', '\xFE').replace('\xFE\xDE', '\xFE')
def stuff(self, s):
return s.replace('\xFC', '\xFE\xDC').replace('\xFD', '\xFE\xDD').replace('\xFE', '\xFE\xDE')

好像不好。每次替换调用都会创建一个新的字符串副本。

迭代器

一个非常 pythonic 的方法是为这个特定问题定义一个迭代器:定义迭代器以将输入数据转换为所需的输出。

def unstuff(data):
i = iter(data)
dic = {'\xDC' : '\xFC', '\xDD' : '\xFD', '\xFE' : '\xDE'}
while True:
d = i.next() # throws StopIteration on the end
if d == '\xFE':
d2 = i.next()
if d2 in dic:
yield dic[d2]
else:
yield '\xFE'
yield d2
else:
yield d

def stuff(data):
i = iter(data)
dic = { '\xFC' : '\xDC', '\xFD' : '\xDD', '\xFE' : '\xDE' }
while True:
d = i.next() # throws StopIteration on the end
if d in dic:
yield '\xFE'
yield dic[d]
else:
yield d

def main():
s = 'hello\xFE\xDCWorld'
unstuffed = "".join(unstuff(s))
stuffed = "".join(stuff(unstuffed))
print s, unstuffed, stuffed

# also possible
for c in unstuff(s):
print ord(c)

if __name__ == '__main__':
main()

stuff()unstuff() 需要一些可迭代的东西(列表、字符串、...)并返回 iterator-object .如果要打印结果或将其传递给socket.send,则需要将其转换回字符串(如"".join(所示) ))。每个意外数据都以某种方式处理:0xFE 0x__ 如果不匹配任何模式,将逐字返回。

正则表达式

另一种方法是使用 regular expressions .这是一个很大的话题,有时也是麻烦的根源,但我们可以保持简单:

import re

s = 'hello\xFE\xDCWorld' # our test-string

# read: FE DC or FE DD or FE DE
unstuff = re.compile('\xFE\xDC|\xFE\xDD|\xFE\xDE')
# read:
# - use this pattern to match against the string
# - replace what you have found (m.groups(0), whole match) with
# char(ord(match[1])^0x20)
unstuffed = unstuff.sub(lambda m: chr(ord(m.group(0)[1])^0x20), s)

# same thing, other way around
stuff = re.compile('\xFC|\xFD|\xFE')
stuffed = stuff.sub(lambda m: '\xFE' + chr(ord(m.group(0))^0x20), unstuffed)

print s, unstuffed, stuffed

如前所述,您必须在某处创建新字符串才能将其用于套接字。至少,这种方法不会像 s.replace(..).replace(..).replace(..) 那样创建不必要的字符串副本。您应该将模式 stuffunstuff 保留在某个地方,因为构建这些对象的成本相对较高。

原生 C 函数

如果某些事情在 python 中会变慢,我们可能想使用 cpython 并将其实现为我们的 C 代码。基本上,我进行第一次运行,计算我有多少字节,分配一个新字符串并进行第二次运行。我不太习惯 python-c-extensions,所以我不想分享这段代码。它似乎有效,请参阅下一章

比较

最重要的优化规则之一:比较!每个测试的基本设置:

generate random binary data as a string
while less_than_a_second:
unstuff(stuff(random_data))
count += 1
return time_needed / count

我知道,设置不是最佳的。但是我们应该得到一些可用的结果:

Comparing 4 methods

我们看到了什么? native 是最快的方法,但仅适用于非常小的字符串。这可能是因为 python 解释器:只需要一个函数调用而不是三个。但大多数时候微秒已经足够快了。在大约 500 字节之后,时间与原始方法几乎相同。在实现过程中一定有一些深奥的魔法在发生。与努力相比,迭代器和 RegExp 是 Not Acceptable 。

总结一下:使用天真的方法。很难得到更好的东西。另外:如果您只是猜测时间,您几乎总是错的。

关于python - 八位字节(字节)填充和取消填充,即用两个或 v.v 替换一个字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13530087/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com