当前位置:首页>python>常见编码与解码详解(Python )

常见编码与解码详解(Python )

  • 2026-10-11 15:50:54
常见编码与解码详解(Python )

为什么需要编码?计算机只认识 0 和 1,所有文本、图片、音视频最终都要变成字节序列才能存储和传输。编码(Encode)就是把人类可读的信息转换成字节序列,解码(Decode)则是逆过程。不同场景对编码有不同的诉求:

1. ASCII 与 Unicode

1.1 ASCII

最早的字符编码,用 7 位二进制表示 128 个字符(英文字母、数字、标点、控制符)。

 ASCII 编码与解码

text = "Hello"# 编码:字符串 → 字节序列encoded = text.encode("ascii")print(encoded)        # b'Hello'print(list(encoded))  # [72, 101, 108, 108, 111]# 解码:字节序列 → 字符串decoded = encoded.decode("ascii")print(decoded)  # Hello

局限:ASCII 只能表示英文,中文、日文、Emoji 等都无法覆盖。

1.2 Unicode 与 UTF-8

Unicode 是字符集(给每个字符分配唯一编号),UTF-8 是编码方式(把编号转换成字节序列)。

UTF-8 编码规则:

text = "编码 Encoding 🚀"# 编码encoded = text.encode("utf-8")print(encoded)# b'\xe7\xbc\x96\xe7\xa0\x81 Encoding \xf0\x9f\x9a\x80'# 查看每个字符占用的字节数for char in "A中🚀":    b = char.encode("utf-8")    print(f"'{char}' → {len(b)} 字节 → {b.hex()}")# 'A' → 1 字节 → 41# '中' → 3 字节 → e4b8ad# '🚀' → 4 字节 → f09f9a80

# 解码

decoded = encoded.decode("utf-8")print(decoded)  # 编码 Encoding 🚀```

 1.3 乱码的本质

乱码就是用错误的编码方式去解码字节序列:

# 用 UTF-8 编码中文

raw = "你好".encode("utf-8")  # b'\xe4\xbd\xa0\xe5\xa5\xbd'# 正确解码print(raw.decode("utf-8"))   # 你好# 错误解码 → 乱码print(raw.decode("latin-1"))  # ä½ å¥½(乱码)print(raw.decode("gbk"))      # 浣犲ソ(乱码,GBK 把 3 字节按 2 字节拆解)

 2. Base64

Base64 把任意二进制数据转换成 64 个可打印 ASCII 字符(`A-Z a-z 0-9 + /`),常用于在文本协议(HTTP、JSON、邮件)中传输二进制数据。

原理:每 3 字节(24 bit)拆成 4 组,每组 6 bit,映射到 Base64 字符表。

原始:  01001000 01100101 01101100   (3字节 = 24 bit)

拆分:  010010  000110  010101  101100 (4组 × 6 bit)

映射:  SG Vs → "SGVs"

# ── 基本用法 ──

import base64text = "Hello, 编码世界!"encoded = base64.b64encode(text.encode("utf-8"))print(encoded)  # b'SGVsbG8sIOe8oeeahOS4lueVjO+8mg=='decoded = base64.b64decode(encoded).decode("utf-8")print(decoded)  # Hello, 编码世界!

# ── URL Safe Base64 ──

# 标准Base64中的 + / 在URL中有特殊含义,URL Safe用 - _ 替换

data = b"\xfb\xff"standard = base64.b64encode(data)      # b'+/8='url_safe = base64.urlsafe_b64encode(data)  # b'-_8='print(f"标准: {standard}, URL Safe: {url_safe}")

# ── Base64 编码图片 ──

import struct# 模拟一个小的 PNG 文件头png_header = b'\x89PNG\r\n\x1a\n'b64_png = base64.b64encode(png_header).decode("ascii")print(f"data:image/png;base64,{b64_png}")# data:image/png;base64,iVBORw0KGgo=

注意:Base64 编码后体积膨胀约 **33%**(3 字节变 4 字节),不适合大文件传输。

 3. Hex 编码(十六进制)

把每个字节直接表示为两个十六进制字符(`0-9 a-f`),编码后体积翻倍但完全可读,常用于哈希值、密钥、MAC 地址的展示。

# ── bytes ↔ hex 字符串 ──

data = b"\x00\xff\x41\x42"hex_str = data.hex()print(hex_str)  # 00ff4142restored = bytes.fromhex(hex_str)print(restored)  # b'\x00\xffAB'

# ── 常见场景:哈希值展示 ──

import hashlibdigest = hashlib.sha256(b"hello").digest()print(digest.hex())#2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824# ── 格式化输出 ──mac = b"\x08\x00\x27\x5c\x8a\x3f"mac_str = ":".join(f"{b:02x}" for b in mac)print(mac_str)  # 08:00:27:5c:8a:3f# ── 大整数编码(如 RSA 模数)──n = 0x00ff4142print(n.to_bytes(4, "big").hex())  # 0000ff4142

 4. URL Encoding(百分号编码)

URL 中只能包含 ASCII 字符的子集,特殊字符和非 ASCII 字符需要用 `%XX` 编码。

from urllib.parse import quote, unquote, urlencode, parse_qs# ── 基本编码 ──# 中文和特殊字符都会被编码url = "https://example.com/search?q=Python 编码&lang=zh"encoded = quote(url, safe="")print(encoded)#ttps%3A%2F%2Fexample.com%2Fsearch%3Fq%3DPython%20%E7%BC%96%E7%A0%81%26lang%3Dzhdecoded = unquote(encoded)print(decoded)  # https://example.com/search?q=Python 编码&lang=zh

# ── 只编码查询参数(推荐做法)──

# safe="/" 保留路径分隔符

print(quote("Python 编码", safe=""))# Python%20%E7%BC%96%E7%A0%81# ── 构建查询字符串 ──params = {"q": "Python 编码", "lang": "zh", "page": 1}query_string = urlencode(params)print(query_string)# q=Python+%E7%BC%96%E7%A0%81&lang=zh&page=1# ── 解析查询字符串 ──parsed = parse_qs(query_string)print(parsed)  # {'q': ['Python 编码'], 'lang': ['zh'], 'page': ['1']}

**编码规则速查**:

 5. HTML Entity Encoding

网页中 `<`、`>`、`&` 等字符有特殊含义,需要转义为 HTML 实体,防止 XSS 注入和渲染错误。

import html# ── 转义 ──raw_html = '<script>alert("XSS & HTML")</script>'escaped = html.escape(raw_html)print(escaped)# &lt;script&gt;alert(&quot;XSS &amp; HTML&quot;)&lt;/script&gt;# ── 反转义 ──original = html.unescape(escaped)print(original)  # <script>alert("XSS & HTML")</script># ── 常见实体 ──entities = {    "<":  "&lt;",    ">":  "&gt;",    "&":  "&amp;",    '"':  "&quot;",    "'":  "&#x27;",}for char, entity in entities.items():    print(f"'{char}' → '{entity}'")

实际应用:在 Web 框架的模板引擎中,默认会对变量输出做 HTML 转义,防止 XSS 攻击。

6. Quoted-Printable

邮件系统(SMTP)传统上只支持 7-bit ASCII,Quoted-Printable 编码让非 ASCII 字符用=XX表示,ASCII 可打印字符保持原样,适合大部分是英文、少量非 ASCII 的内容。

import quopri# ── 编码 ──text = "Hello 编码世界, this is a test."encoded = quopri.encodestring(text.encode("utf-8"))print(encoded)# b'Hello =E7=BC=96=E7=A0=81=E4=B8=96=E7=95=8C, this is a test.'

# ── 解码 ──

decoded = quopri.decodestring(encoded).decode("utf-8")print(decoded)  # Hello 编码世界, this is a test.

 对比 Base64:QP 保持英文可读,Base64 全部变成不可读

import base64print(base64.b64encode(text.encode("utf-8")))# b'SGVsbG8g57yQ56CB5LiW55WM77yI...

 7. 完整对比

各种编码方式对比演示

import base64import quopriimport htmlfrom urllib.parse import quoteoriginal = "Hello 编码 🚀"results = {    "UTF-8 Hex":   original.encode("utf-8").hex(),    "Base64":      base64.b64encode(original.encode("utf-8")).decode(),    "URL Encode":  quote(original, safe=""),    "HTML Escape": html.escape(original),    "Quoted-Print": quopri.encodestring(original.encode("utf-8")).decode(),}print(f"原始文本: {original}")print(f"UTF-8 字节: {original.encode('utf-8')}")print(f"字节数: {len(original.encode('utf-8'))}")print("-" * 60)for name, encoded in results.items():    print(f"{name:15s} → {encoded}")

输出:

 编码选型决策

要在文本协议中传输二进制?

 核心原则:

编码不是加密。所有上述编码方式都是公开标准,任何人都能解码。编码的目的是兼容性(让数据能安全通过不同通道),不是保密性。如果需要保密,请使用 AES、RSA 等加密算法。

最新文章

随机文章