chr 和 ord 在處理字節(jié)和十六進制字符時的妙用

之前我分析用十六進制字符串表示的數(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 碼的形式顯示的,顯示效果大概如下:

在VSCode 中用 hexdump 查看 python.exe 文件

而如果指定了編碼或采用了系統(tǒng)自帶編碼打開二進制文件谬返,直接顯示里面會包含一些生僻漢字等:

在 Hex Editor Neo 中打開 python.exe 文件

由此可以推斷一下之斯,如果編址不是一個字節(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ā)覺有點寫跑題了……

總的來說梁沧,ordchr 用來處理單字節(jié)和數(shù)值之間的轉(zhuǎn)換還挺方便的檀何,不用導(dǎo)入其他模塊,前置用于“解碼”,后者用于”壓縮”频鉴。

然后這里也順便總結(jié)一下數(shù)值及其壓縮格式的轉(zhuǎn)換:

  • 涉及到位的處理栓辜,轉(zhuǎn)換至二進制字符串是一個不錯的選擇。
  • 數(shù)值的存儲的話垛孔,字節(jié)格式占用的空間最小藕甩,但最不方便閱讀。
  • 十六進制字符串格式既方便閱讀周荐,也在一定程度上便于進行位操作狭莱,是字節(jié)和二進制字符串之間的折中。

字節(jié)與十進制數(shù)值之間的轉(zhuǎn)換

byte2dec

  1. 直接利用內(nèi)置類型方法 int.from_bytes
    >>> 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
    
    這里要著重注意的是大端小端的問題概作,一定要明確字節(jié)存儲所采用的的方式是大端還是小端腋妙。
  2. struct.unpack
    >>> import struct
    >>> byte = bytes.fromhex("bf214802")
    >>> dec = struct.unpack("<I", byte)[0]
    >>> dec
    38281663
    
    具體參考官方文檔
  3. 自定義函數(shù)

dec2byte

  1. 先格式化為十六進制字符串再轉(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
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末讯榕,一起剝皮案震驚了整個濱河市骤素,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌愚屁,老刑警劉巖济竹,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異集绰,居然都是意外死亡规辱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門栽燕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來罕袋,“玉大人,你說我怎么就攤上這事碍岔≡⊙叮” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵蔼啦,是天一觀的道長榆纽。 經(jīng)常有香客問我,道長捏肢,這世上最難降的妖魔是什么奈籽? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮鸵赫,結(jié)果婚禮上衣屏,老公的妹妹穿的比我還像新娘。我一直安慰自己辩棒,他們只是感情好狼忱,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布膨疏。 她就那樣靜靜地躺著,像睡著了一般钻弄。 火紅的嫁衣襯著肌膚如雪佃却。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天窘俺,我揣著相機與錄音饲帅,去河邊找鬼。 笑死批销,一個胖子當(dāng)著我的面吹牛洒闸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播均芽,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼单鹿!你這毒婦竟也來了掀宋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤仲锄,失蹤者是張志新(化名)和其女友劉穎劲妙,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體儒喊,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡镣奋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了怀愧。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片侨颈。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖芯义,靈堂內(nèi)的尸體忽然破棺而出哈垢,到底是詐尸還是另有隱情,我是刑警寧澤扛拨,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布耘分,位于F島的核電站,受9級特大地震影響绑警,放射性物質(zhì)發(fā)生泄漏求泰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一计盒、第九天 我趴在偏房一處隱蔽的房頂上張望渴频。 院中可真熱鬧,春花似錦章郁、人聲如沸枉氮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽聊替。三九已至楼肪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惹悄,已是汗流浹背春叫。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留泣港,地道東北人暂殖。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像当纱,于是被迫代替她去往敵國和親呛每。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350