3

次のようなデバイスから情報を読み取るために PySerial (Python 2.7) を使用しています。

バッファ += ser.read(3)

これで、str 型のバッファ (つまり 0xAE0259) に 3 バイトあります。私は Python を初めて使用するので、3 バイトの左端 (0xAE) を切り取り、残りの 2 バイトを int として解釈する「pythonian」の方法を探しています。最初にビット マスクを考えました: buffer &= 0xFFFF ですが、Python では str でビット演算子を使用できません。バッファを int に変換しようとしても失敗しました。次に、BitArray からビットの範囲をスライスできる「bitstring モジュール」について読みましたが、これを使用するのは少しやり過ぎだと思いますか?

4

5 に答える 5

2

マルチバイトタイプがビッグエンディアンかリトルエンディアンか、および符号付きか符号なしかを知る必要があります。2バイトが符号なしのビッグエンディアンのショートであると仮定すると、次のようになります。

>>> buf = '\xAE\x02\x59'
>>> from struct import unpack
>>> unpack('>BH', buf)
(174, 601)

'>'はビッグエンディアンを意味します。「B」は、不要な最初の符号なしバイトです。「H」はunsignedshortです。

于 2011-07-06T19:14:23.683 に答える
1

それには2つの簡単な方法があります。1 つの方法は、バッファーを 16 進数の整数に変換し、ビットマスクを使用して最後の 32 ビットを取得することです。もう 1 つは、スライス演算子を使用して最後の 4 文字を取得し、その残りを 16 進整数として解釈する方法です。

>>> buffer = 'AE0259'
>>> print int(buffer, 16) & 0xFFFF
601
>>> print int(buffer[-4:], 16) 
601

編集 - eryksun には正しい答えがありますが、実際の使用例の例を更新したかったのです。

>>> buffer = '\xAE\x02\x59'
>>> # print the integer value of the last two binary "characters"
>>> print sum((ord(x) << i*8 for i,x in enumerate(buffer[:-2-1:-1])))
601
>>> # print the integer value all binary "characters" 
>>> # with a bitmask of the lower 32 digits
>>> print sum((ord(x) << i*8 for i,x in enumerate(buffer[::-1]))) & 0xFFFF
601
于 2011-07-06T14:01:30.533 に答える
1

バイトアンパッキングのみを行う必要がある場合、structモジュールはbytearrayタイプと同様にあなたの友人です(eryksunの回答を参照):

>>> ba = bytearray('\xae\x02\x59')

これにより、バイトレベルでのインデックスとスライスが可能になります

>>> hex(ba[0])
'0xae'
>>> ba[1:3]
bytearray(b'\x02Y')

struct複数のバイトを int に変換するという点では、これは非常に役立ちますが、通常とは異なるバイト長でない限り、これ以上の成果を上げることはまずありません。int への 2 バイト変換は次のようになります。

>>> (ba[1] << 8) + ba[2]
601

あなたはコメントで、ビット単位のスライスも行う一般的な方法が欲しいと言っています。申し訳ありませんが、1 つもありません。開始するのに最適な場所は、バイト配列からのシフトとマスキングです。そのため、 bitstringのようなモジュールが便利です (私が書きました) - エラーが発生しやすい面倒なことを他の誰かに任せることができます!

>>> b = bitstring.Bits(ba)
>>> b[8:].uint
601
>>> b.unpack('hex:8, uint:16')
['ae', 601]
于 2011-07-07T21:57:35.720 に答える
0

@ironchefpythonは、バッファが実際にはバイナリデータで構成されていることをコメントが示していることを除いて、何を使用すべきかを提案しました。それが事実であると仮定すると、このソリューションは機能するはずですが、あまりエレガントではありません。

from struct import unpack
def strmask(buffer, mask):
   #calculate the number of bytes to extract
   mask_length = mask.bit_length() / 8  + (1 if mask.bit_length() % 8 > 0 else 0)
   #extract those bytes and put them into a Python int, then perform the mask
   return mask & reduce(lambda l,r: (l<<8)+r, unpack("B" * mask_length, buffer[-1 * mask_length:]))

これにより、必要な結果が得られます。たとえば、次のようになります。

>>> print strmask('\xAE\x02\x59', 0xFFFF)
601
于 2011-07-06T19:11:37.187 に答える
0

が文字列の場合buffer、次のように文字列をトリミングして、残りの文字を「切り取る」ことができます。

newstr = buffer[1:]
于 2011-07-06T13:34:36.613 に答える