Bytes 位元運算
在處理二進位資料時,位元運算(Bitwise Operations)是不可或缺的工具。無論是資料加 密、校驗碼計算,還是效能優化,理解 XOR、OR、AND 這些基本運算都能讓你的程式碼更強大且高效。
🔢 什麼是位元運算?
位元運算直接操作資料的二進位表示,**逐位元(bit by bit)**進行運算。在 Python 中,bytes 物件支援這些操作,讓我們能夠高效地處理二進位資料。
基本規則表
| A | B | AND (∧) | OR (∨) | XOR (⊕) |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 1 | 1 |
| 1 | 0 | 0 | 1 | 1 |
| 1 | 1 | 1 | 1 | 0 |
⚙️ Python Bytes 位元運算語法
在 Python 中,bytes 物件支援三種位元運算符號:
&:AND(按位與)|:OR(按位或)^:XOR(按位異或)
⚠️ 重要限制: 兩個 bytes 物件必須長度相同才能進行位元運算。
# ✅ 正確:長度相同
result = b'\x01\x02' & b'\x03\x04'
# ❌ 錯誤:長度不同會拋出 TypeError
result = b'\x01' & b'\x02\x03' # TypeError: operands must be of equal length
🔷 AND 運算(&):按位與
AND 運算會將兩個位元組的對應位元進行「與」運算,只有當兩個位元都是 1 時,結果才是 1。
基本用法
a = b'\x0F' # 0000 1111 (二進位)
b = b'\x33' # 0011 0011 (二進位)
result = bytes(a[0] & b[0] for a, b in zip(a, b))
# 結果: 0x03
# 計算過程:
# 0000 1111 (0x0F)
# & 0011 0011 (0x33)
# -----------
# 0000 0011 (0x03)
實際應用:遮罩(Masking)
AND 運算常用於遮罩操作,用來提取或清除特定的位元:
def extract_low_nibble(byte_value: int) -> int:
"""提取低 4 位元(低半位元組)"""
mask = 0x0F # 0000 1111
return byte_value & mask
def extract_high_nibble(byte_value: int) -> int:
"""提取高 4 位元(高半位元組)"""
mask = 0xF0 # 1111 0000
return (byte_value & mask) >> 4
def clear_bits(data: bytes, mask: bytes) -> bytes:
"""使用遮罩清除特定位元(1 表示保留,0 表示清除)"""
return bytes(d & m for d, m in zip(data, mask))
# 使用範例
value = 0xAB # 1010 1011
low = extract_low_nibble(value) # 0xB
high = extract_high_nibble(value) # 0xA
original = b'\xFF\xFF'
clear_mask = b'\xF0\x0F' # 清除第一個位元組的低 4 位和第二個位元組的高 4 位
cleared = clear_bits(original, clear_mask) # b'\xF0\x0F'
🔶 OR 運算(|):按位或
OR 運算會將兩個位元組的對應位元進行「或」運算,只要其中一個位元是 1,結果就是 1。
基本用法
a = b'\x0F' # 0000 1111
b = b'\x30' # 0011 0000
result = bytes(a[0] | b[0] for a, b in zip(a, b))
# 結果: 0x3F
# 計算過程:
# 0000 1111 (0x0F)
# | 0011 0000 (0x30)
# -----------
# 0011 1111 (0x3F)
實際應用:設定位元(Setting Bits)
OR 運算常用於設定特定位元為 1:
def set_bits(data: bytes, mask: bytes) -> bytes:
"""使用遮罩設定特定位元為 1(1 表示設定,0 表示保持原樣)"""
return bytes(d | m for d, m in zip(data, mask))
def set_flag(byte_value: int, bit_position: int) -> int:
"""設定指定位元為 1(bit_position: 0-7,0 是最低位元)"""
mask = 1 << bit_position
return byte_value | mask
# 使用範例
original = b'\x00\x00'
set_mask = b'\xF0\x0F' # 設定第一個位元組的高 4 位和第二個位元組的低 4 位
set_result = set_bits(original, set_mask) # b'\xF0\x0F'
value = 0x00
value = set_flag(value, 3) # 設定第 3 位元 → 0x08 (0000 1000)
🔸 XOR 運算(^):按位異或
XOR 運算是最有趣的位元運算,當兩個位元不同時結果為 1,相同時結果為 0。
基本用法
a = b'\x0F' # 0000 1111
b = b'\x33' # 0011 0011
result = bytes(a[0] ^ b[0] for a, b in zip(a, b))
# 結果: 0x3C
# 計算過程:
# 0000 1111 (0x0F)
# ^ 0011 0011 (0x33)
# -----------
# 0011 1100 (0x3C)
XOR 的重要特性
XOR 運算有幾個非常有用的特性:
| 特性 | 說明 | 範例 |
|---|---|---|
| 可逆性 | A ^ B ^ B = A | 加密後再 XOR 一次就能解密 |
| 交換律 | A ^ B = B ^ A | 運算順序不影響結果 |
| 結合律 | (A ^ B) ^ C = A ^ (B ^ C) | 可以任意組合 |
| 自反性 | A ^ A = 0 | 相同值 XOR 結果為 0 |
實際應用 1:簡單加密/解密
利用 XOR 的可逆性,我們可以實現簡單的加密:
def simple_xor_cipher(data: bytes, key: bytes) -> bytes:
"""
使用 XOR 進行簡單的加密/解密
注意:這只是教學範例,不適合生產環境使用!
"""
if not key:
raise ValueError("金鑰不能為空")
# 循環使用金鑰
key_cycle = (key * ((len(data) // len(key)) + 1))[:len(data)]
return bytes(d ^ k for d, k in zip(data, key_cycle))
# 使用範例
plaintext = b"Hello, World!"
key = b"SECRET"
# 加密
encrypted = simple_xor_cipher(plaintext, key)
# 解密(XOR 的特性:加密和解密是同一個操作)
decrypted = simple_xor_cipher(encrypted, key)
assert decrypted == plaintext # True
實際應用 2:校驗碼計算
XOR 常用於計算簡單的校驗碼:
def calculate_xor_checksum(data: bytes) -> int:
"""計算 XOR 校驗碼"""
checksum = 0
for byte in data:
checksum ^= byte
return checksum
def verify_xor_checksum(data: bytes, expected_checksum: int) -> bool:
"""驗證 XOR 校驗碼"""
return calculate_xor_checksum(data) == expected_checksum
# 使用範例
message = b"Hello, World!"
checksum = calculate_xor_checksum(message)
is_valid = verify_xor_checksum(message, checksum) # True
實際應用 3:交換變數值(不使用暫存變數)
雖然這在 bytes 中不常用,但展示了 XOR 的巧妙應用:
def swap_without_temp(a: int, b: int) -> tuple[int, int]:
"""使用 XOR 交換兩個整數值(不使用暫存變數)"""
a = a ^ b # a 現在包含 a 和 b 的差異
b = a ^ b # b 現在等於原始的 a
a = a ^ b # a 現在等於原始的 b
return a, b
# 使用範例
x, y = 10, 20
x, y = swap_without_temp(x, y)
# 結果: x=20, y=10