【Python】bytes和hex字符串之间的相互转换。

Python中bytes与hex转换
本文介绍了Python2.7及Python3环境下bytes类型与十六进制(hex)字符串间的转换方法。包括不同Python版本中使用的方法及其语法差异。

【Python】bytes和hex字符串之间的相互转换。
反复在几个环境上折腾码流的拼装解析和可读化打印,总是遇到hex字符串和bytes之间的转换,记录在这里吧。

  1. 在Python2.7.x上(更老的环境真心折腾不起),hex字符串和bytes之间的转换是这样的:
>>> a = 'aabbccddeeff'
>>> a_bytes = a.decode('hex')
>>> print(a_bytes)
b'\xaa\xbb\xcc\xdd\xee\xff'
>>> aa = a_bytes.encode('hex')
>>> print(aa)
aabbccddeeff
>>>
  1. 在python 3环境上,因为string和bytes的实现发生了重大的变化,这个转换也不能再用encode/decode完成了。

2.1 在python3.5之前,这个转换的其中一种方式是这样的:

>>> a = 'aabbccddeeff'
>>> a_bytes = bytes.fromhex(a)
>>> print(a_bytes)
b'\xaa\xbb\xcc\xdd\xee\xff'
>>> aa = ''.join(['%02x' % b for b in a_bytes])
>>> print(aa)
aabbccddeeff
>>>

2.2 到了python 3.5之后,就可以像下面这么干了:

>>> a = 'aabbccddeeff'
>>> a_bytes = bytes.fromhex(a)
>>> print(a_bytes)
b'\xaa\xbb\xcc\xdd\xee\xff'
>>> aa = a_bytes.hex()
>>> print(aa)
aabbccddeeff
>>>
last
data = b'\x820\xb100\x03\xc3\xb4'
print('type(data) = ', type(data))
#type(data) =  <class 'bytes'>


lst = list(data)
print(lst)
print(type(lst[0]))
#[130, 48, 177, 48, 48, 3, 195, 180]
#<class 'int'>

tmp = data.hex()

print(type(tmp), tmp)
# <class 'str'> 8230b1303003c3b4

strr = '8230b1303003c3b4'

num = bytes.fromhex(strr)

print(type(num), num)
# <class 'bytes'> b'\x820\xb100\x03\xc3\xb4'
<think>我们通常使用Python内置函数`int()`将十六进制字符串转换为整数。 如果字符串以'0x'开头,可以直接使用int(hex_string, 16)转换。 如果字符串不带'0x',同样可以使用int(hex_string, 16)。 另外,如果我们需要将十六进制字符串转换为字节数据,可以使用`bytes.fromhex()`。 如果我们需要将十六进制字符串转换为浮点数,可能需要先转换为整数,然后再进行解释(例如使用struct模块)。 下面给出几个示例:</think># Python 中十六进制字符串转数字的完整指南 在 Python 中,将十六进制字符串转换为数字有多种方法,下面我将详细介绍各种方法及其适用场景。 ## 1. 使用内置函数 `int()` 这是最直接的方法,适用于将十六进制字符串转换为整数。 ```python # 基本用法 hex_str = "1a3f" num = int(hex_str, 16) print(f"十六进制 {hex_str} 转换为整数: {num}") # 输出: 6719 # 处理带前缀的十六进制字符串 hex_str_with_prefix = "0x1a3f" if hex_str_with_prefix.startswith(("0x", "0X")): num = int(hex_str_with_prefix, 0) # 使用0让Python自动识别进制 else: num = int(hex_str_with_prefix, 16) print(f"带前缀的十六进制 {hex_str_with_prefix} 转换为整数: {num}") # 输出: 6719 # 处理负数(使用补码表示) negative_hex = "-0x1a3f" num = int(negative_hex, 0) print(f"负十六进制 {negative_hex} 转换为整数: {num}") # 输出: -6719 ``` ### 参数说明: - 第一个参数:要转换字符串 - 第二个参数:进制(16 表示十六进制) - 使用 `0` 作为进制参数时,Python 会自动识别前缀(0x/0X 表示十六进制) ## 2. 使用 `ast.literal_eval()` 安全转换 当处理不可信的输入时,推荐使用此方法,比 `eval()` 更安全。 ```python import ast hex_str = "0x1a3f" # 安全转换 num = ast.literal_eval(hex_str) print(f"使用 ast.literal_eval 转换: {num}") # 输出: 6719 # 处理不带前缀的情况 hex_str_no_prefix = "1a3f" try: num = ast.literal_eval("0x" + hex_str_no_prefix) print(f"添加前缀后转换: {num}") # 输出: 6719 except ValueError: # 如果无法转换,尝试使用int() num = int(hex_str_no_prefix, 16) ``` ## 3. 转换为浮点数 如果需要将十六进制字符串转换为浮点数,可以使用 `struct` 模块: ```python import struct # IEEE 754 浮点数转换 def hex_to_float(hex_str): # 去除前缀并填充到8个字符(32位浮点数) hex_str = hex_str.replace("0x", "").replace("0X", "").zfill(8) # 转换为字节 byte_data = bytes.fromhex(hex_str) # 小端序转换 return struct.unpack('>f', byte_data)[0] # 使用 '>f' 表示大端序,'<f' 表示小端序 # 示例 hex_float = "40490fdb" # 3.1415927410125732 的十六进制表示 float_num = hex_to_float(hex_float) print(f"十六进制 {hex_float} 转换为浮点数: {float_num:.10f}") # 输出: 3.1415927410 ``` ## 4. 处理大端序/小端序 当处理来自网络或文件系统的数据时,需要考虑字节顺序: ```python def hex_to_int(hex_str, byteorder='big'): # 去除前缀 hex_str = hex_str.replace("0x", "").replace("0X", "") # 确保长度为偶数 if len(hex_str) % 2 != 0: hex_str = '0' + hex_str # 转换为字节 byte_data = bytes.fromhex(hex_str) # 根据字节顺序转换 return int.from_bytes(byte_data, byteorder=byteorder) # 示例 hex_big_endian = "00FF" # 大端序: 255 hex_little_endian = "FF00" # 小端序: 255 print(f"大端序转换: {hex_to_int(hex_big_endian, 'big')}") # 输出: 255 print(f"小端序转换: {hex_to_int(hex_little_endian, 'little')}") # 输出: 255 ``` ## 5. 处理带符号的十六进制(补码表示) ```python def hex_to_signed_int(hex_str, bits=32): """将十六进制字符串转换为带符号整数""" hex_str = hex_str.replace("0x", "").replace("0X", "") unsigned = int(hex_str, 16) # 计算最大值(基于位数) max_val = 2**bits # 如果超过有符号范围的一半,则为负数 if unsigned >= max_val/2: return unsigned - max_val else: return unsigned # 示例 hex_signed = "FFFF" # 16位有符号整数的 -1 print(f"有符号转换 (16位): {hex_to_signed_int(hex_signed, 16)}") # 输出: -1 hex_signed_32 = "FFFFFFF0" # 32位有符号整数的 -16 print(f"有符号转换 (32位): {hex_to_signed_int(hex_signed_32, 32)}") # 输出: -16 ``` ## 6. 完整实用类 ```python class HexConverter: @staticmethod def to_int(hex_str, byteorder='big', signed=False): """将十六进制字符串转换为整数 参数: hex_str: 十六进制字符串 byteorder: 字节顺序 ('big' 或 'little') signed: 是否解释为有符号整数 """ # 清理输入 hex_str = hex_str.strip().replace("0x", "").replace("0X", "") # 确保长度为偶数 if len(hex_str) % 2 != 0: hex_str = '0' + hex_str # 转换为字节 try: byte_data = bytes.fromhex(hex_str) except ValueError: raise ValueError(f"无效的十六进制字符串: {hex_str}") # 计算位数 bits = len(byte_data) * 8 # 转换为整数 return int.from_bytes(byte_data, byteorder=byteorder, signed=signed) @staticmethod def to_float(hex_str, byteorder='big'): """将十六进制字符串转换为IEEE 754浮点数""" hex_str = hex_str.strip().replace("0x", "").replace("0X", "") # 检查长度 (4字节为单精度,8字节为双精度) if len(hex_str) == 8: fmt = 'f' # 单精度 elif len(hex_str) == 16: fmt = 'd' # 双精度 else: raise ValueError("十六进制长度必须是8(单精度)或16(双精度)个字符") # 确保长度为偶数 if len(hex_str) % 2 != 0: hex_str = '0' + hex_str # 转换为字节 byte_data = bytes.fromhex(hex_str) # 确定字节顺序 endian = '>' if byteorder == 'big' else '<' # 解包 return struct.unpack(f'{endian}{fmt}', byte_data)[0] # 使用示例 converter = HexConverter() # 转换整数 print("整数转换:") print(converter.to_int("1a3f")) # 6719 print(converter.to_int("0x1a3f", signed=True)) # 6719 print(converter.to_int("FF", byteorder='little', signed=True)) # -1 (8位有符号) # 转换浮点数 print("\n浮点数转换:") print(converter.to_float("40490fdb")) # 3.1415927410125732 (π) print(converter.to_float("400921fb54442d18")) # 3.141592653589793 (π双精度) ``` ## 常见问题及解决方案 | 问题类型 | 错误示例 | 解决方案 | |----------|----------|----------| | 无效字符 | `int("1g3f", 16)` | 使用异常处理:`try-except ValueError` | | 长度问题 | 奇数长度字符串 | 使用 `zfill()` 或添加前导零 | | 字节顺序 | 网络数据转换错误 | 明确指定 `byteorder='big'` 或 `'little'` | | 浮点精度 | 转换后精度损失 | 使用双精度(8字节)表示 | | 符号问题 | 补码转换错误 | 使用 `signed=True` 参数 | | 大数处理 | 超过 `sys.maxsize` | Python 自动处理大整数 | ## 性能比较 ```python import timeit # 测试不同方法的性能 hex_str = "1a3f" * 100 # 长十六进制字符串 def test_int(): return int(hex_str, 16) def test_literal_eval(): return ast.literal_eval("0x" + hex_str) def test_bytes_conversion(): return int.from_bytes(bytes.fromhex(hex_str), 'big') print("int() 方法:", timeit.timeit(test_int, number=1000)) print("literal_eval 方法:", timeit.timeit(test_literal_eval, number=1000)) print("bytes 方法:", timeit.timeit(test_bytes_conversion, number=1000)) ``` **典型结果**: - `int()` 方法最快 - `bytes` 方法适合处理字节顺序 - `literal_eval` 最慢但最安全 ## 实际应用场景 1. **网络协议解析**:处理 TCP/UDP 数据包中的十六进制字段 2. **硬件寄存器读取**:与嵌入式设备通信 3. **文件格式解析**:分析二进制文件格式(如PNG、ELF) 4. **加密算法**:处理密钥哈希值 5. **数据转换**:将传感器数据从十六进制转为数值
评论 15
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值