之前我分析用十六進制字符串表示的數(shù)值時習(xí)慣用 int(hexStr, 16)
的方法來解析烤送,十六進制字符串轉(zhuǎn)至byte存儲時習(xí)慣使用 bytes.fromhex(hexStr)
鸽疾,然后字節(jié)解析至對應(yīng)數(shù)值時習(xí)慣用 struct.unpack("<I", byte)[0]
憎妙,轉(zhuǎn)存至十六進制字符串格式時習(xí)慣使用 thisByte.hex()
,然后今天在對前人遺留代碼進行考古時瘾婿,發(fā)現(xiàn)他在獲取數(shù)據(jù)幀中某些單字節(jié)字段的域的值時用的是 ord
谒所,這個作為一個內(nèi)置函數(shù)確實很好用缨称。
ord
以一個字符(長度為 1 的字符串)作為參數(shù),返回對應(yīng)的 ASCII 數(shù)值郁岩,或者 Unicode 數(shù)值婿奔,如果所給的 Unicode 字符超出了你的 Python 定義范圍,則會引發(fā)一個 TypeError 的異常(摘自菜鳥教程)问慎。
>>> ord('a')
97
>>> ord('A')
65
>>> ord('ú')
250
>>> ord('哈')
21704
>>> ord('哈哈')'
File "<stdin>", line 1
ord('哈哈')'
^
SyntaxError: EOL while scanning string literal
>>>
從上可以看出萍摊,甚至還可以用中文來壓縮存儲數(shù)值信息(但這里的中文其實已經(jīng)遠(yuǎn)遠(yuǎn)超出ASCII碼的范圍了,這一點得注意)如叼。
而由于目前我這里只需要處理字節(jié)數(shù)據(jù)冰木, 1 Byte = 8 bit,所以 ASCII 碼 0 ~ 255 的范圍已經(jīng)足夠應(yīng)付很多幀字段的取值了笼恰。
而之所以我們在編輯器里直接打開二進制文件顯示亂碼踊沸,我想,是因為計算機一般是以字節(jié)編址的社证,一字節(jié)有八位逼龟,剛好可以與 ASCII 碼表對應(yīng)(其實我這里應(yīng)該是說反了,當(dāng)初 ASCII 碼表的制定基于英文追葡,加上數(shù)字及常用符號和一些不可見的控制符號腺律,剛好湊出來的256個剛好夠 8 個位也就是 1 字節(jié);而不是字節(jié)主動去迎合 ASCII 碼表)宜肉,于是不指定任何編碼標(biāo)準(zhǔn)直接打開二進制文件的話匀钧,默認(rèn)是以 ASCII 碼的形式顯示的,顯示效果大概如下:
而如果指定了編碼或采用了系統(tǒng)自帶編碼打開二進制文件谬返,直接顯示里面會包含一些生僻漢字等:
由此可以推斷一下之斯,如果編址不是一個字節(jié),而是三或四個字節(jié)的話朱浴,估計打開二進制文件吊圾,也許可以直接看得到我們常用的某些漢字了哈哈(這里有一篇關(guān)于 Unicode 編碼范圍的博文寫得挺詳細(xì)的)。
然后與之對應(yīng)的 chr
翰蠢,我們來看一下 Python 解釋器給出的幫助:
>>> help(chr)
Help on built-in function chr in module builtins:
chr(i, /)
Return a Unicode string of one character with ordinal i; 0 <= i <= 0x10ffff.
>>> help(ord)
Help on built-in function ord in module builtins:
ord(c, /)
Return the Unicode code point for a one-character string.
>>> 0x10ffff
1114111
可以得知 chr
是給定一個數(shù)值(不能超過 1114111)项乒,返回一個 Unicode 碼。
>>> chr(0)
'\x00'
>>> chr(97)
'a'
>>> chr(20521)
'倩'
>>>
突然發(fā)覺有點寫跑題了……
總的來說梁沧,ord
和 chr
用來處理單字節(jié)和數(shù)值之間的轉(zhuǎn)換還挺方便的檀何,不用導(dǎo)入其他模塊,前置用于“解碼”,后者用于”壓縮”频鉴。
然后這里也順便總結(jié)一下數(shù)值及其壓縮格式的轉(zhuǎn)換:
- 涉及到位的處理栓辜,轉(zhuǎn)換至二進制字符串是一個不錯的選擇。
- 數(shù)值的存儲的話垛孔,字節(jié)格式占用的空間最小藕甩,但最不方便閱讀。
- 十六進制字符串格式既方便閱讀周荐,也在一定程度上便于進行位操作狭莱,是字節(jié)和二進制字符串之間的折中。
字節(jié)與十進制數(shù)值之間的轉(zhuǎn)換
byte2dec
- 直接利用內(nèi)置類型方法
int.from_bytes
這里要著重注意的是大端小端的問題概作,一定要明確字節(jié)存儲所采用的的方式是大端還是小端腋妙。>>> help(int.from_bytes) Help on built-in function from_bytes: from_bytes(bytes, byteorder, *, signed=False) method of builtins.type instance Return the integer represented by the given array of bytes. bytes Holds the array of bytes to convert. The argument must either support the buffer protocol or be an iterable object producing bytes. Bytes and bytearray are examples of built-in objects that support the buffer protocol. byteorder The byte order used to represent the integer. If byteorder is 'big', the most significant byte is at the beginning of the byte array. If byteorder is 'little', the most significant byte is at the end of the byte array. To request the native byte order of the host system, use `sys.byteorder' as the byte order value. signed Indicates whether two's complement is used to represent the integer. >>> int.from_bytes(b'y\xcc\xa6\xbb', byteorder='big') 2043455163 >>> int.from_bytes(b'y\xcc\xa6\xbb', byteorder='little') 3148270713
-
struct.unpack
具體參考官方文檔。>>> import struct >>> byte = bytes.fromhex("bf214802") >>> dec = struct.unpack("<I", byte)[0] >>> dec 38281663
- 自定義函數(shù)
dec2byte
- 先格式化為十六進制字符串再轉(zhuǎn)至字節(jié)
>>> dec = 12345 >>> byte = bytes.fromhex("{:08x}".format(dec)) >>> byte b'\x00\x0009' >>> byte[::-1] b'90\x00\x00
2.struct.pack
>>> dec = 12345 >>> import struct >>> struct.pack(">I", dec) b'\x00\x0009' >>> struct.pack("<I", dec) b'90\x00\x00'
字節(jié)與十六進制字符串之間的轉(zhuǎn)換
byte2hexStr
def frame2hexStr(frame):
hexStr = frame.hex()
return hexStr
hexStr2byte
def hexStr2frame(hexStr):
frame = bytes.fromhex(hexStr)
return frame
字節(jié)與二進制字符串之間的轉(zhuǎn)換
byte2binStr
binStr2byte
十六進制字符串與二進制字符串之間的轉(zhuǎn)換
hexStr2binStr
def hexStr2binStr(hexStr):
dec = int(hexStr, 16)
bl = len(hexStr) * 4
binStr = "{:0{}b}".format(dec, bl)
return binStr
binStr2hexStr
- 純手工
import math def binStr2hexStr(binStr): lenB = len(binStr) zerofilled = binStr.zfill(4 * math.ceil(lenB/4)) tempList = [hex(int(zerofilled[i*4: (i+1)*4], 2))[2:] for i in range(lenB//4+1)] hexStr = "".join(tempList) return hexStr
- 以十進制數(shù)為轉(zhuǎn)換中介
def binStr2hexStr(binStr): dec_value = int(binStr, 2) hexStr = hex(dec_value)[2:] return hexStr