看懂 Unicode 与 UTF-8 编码全过程

在自然语言处理中(NLP),文本是模型的输入,但计算机并不能直接理解“字”,而是通过数字和二进制来存储和处理字符。这篇文章将以中文 "你"为例,详细讲解从 Unicode 码点 → UTF-8 字节序列 的全过程,并配合 Python 代码逐步验证。

本文将介绍以下内容:

  • 1. Unicode 与 UTF-8 的背景
  • 2. 示例:汉字 “你” 的编码过程
  • 3. UTF-8 三字节协议的设计原因
  • 4. 总结整体代码x
  • 5. 如何快速确认文本需要几个字节表示
  • 6. 总结

一、Unicode 与 UTF-8 的背景

1. Unicode:通用字符集

Unicode 是一种 字符集,旨在涵盖地球上几乎所有的书写系统和字符。它为每个字符分配了一个唯一的 代码点(code point) 来标识字符。

  • 例如 "你" 的 Unicode 码点是 U+4F60
  • Unicode 不关心字符在计算机内部的存储方式,它只是定义了字符与号码的对应关系。

Unicode 的出现,解决了过去不同语言使用不同编码导致的“乱码”和“碎片化”问题,让所有字符都能在一个统一的标准下共存。


2. UTF-8:Unicode 的存储方式

Unicode 只提供“码点”,但实际存储时需要具体的 编码方案。其中使用最广泛的就是 UTF-8

UTF-8(Unicode Transformation Format - 8)是一种 变长字符编码

  • 兼容 ASCII:所有 ASCII 字符(U+0000 – U+007F)直接用 1 个字节表示,不会有任何变化。
  • 多字节编码:更大的 Unicode 码点会使用 2~4 个字节存储。
  • 每个字节的前缀位(高位)用于指示字符的长度与字节角色。

规则如下:

  1. 单字节符(0x00–0x7F):0xxxxxxx
  2. 双字节符(0x80–0x07FF):110xxxxx 10xxxxxx
  3. 三字节符(0x0800–0xFFFF):1110xxxx 10xxxxxx 10xxxxxx
  4. 四字节符(0x10000–0x10FFFF):11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

因此 UTF-8 可以覆盖整个 Unicode 字符集,并且保证 ASCII 文件和 UTF-8 文件完全兼容。


二、示例:汉字 "你" 的编码过程

我们现在用 "你" 来演示 Unicode 与 UTF-8 转换的全过程。


步骤 1:获取 Unicode 码点

char = "你"
code_point = ord(char)  # 获取 Unicode 码点
print(hex(code_point), code_point)

输出:

0x4f60 20320

说明 "你" 的 Unicode 码点是 U+4F60(十进制 20320)。


步骤 2:转成二进制

binary_repr = bin(code_point)[2:].zfill(16)  # 转成16位二进制
print(binary_repr)

输出:

0100111101100000

步骤 3:确定 UTF-8 模板

根据 UTF-8 的规则:

  • U+4F60 位于 0x0800–0xFFFF
  • 所以 "你" 需要用 3 个字节表示,模板是:
1110xxxx 10xxxxxx 10xxxxxx

步骤 4:填充二进制位

0100 1111 0110 0000(16 位)依次填入模板中的 x

bits = binary_repr
byte1 = "1110" + bits[:4]      # 高4位
byte2 = "10" + bits[4:10]      # 中间6位
byte3 = "10" + bits[10:]       # 低6位

print(byte1, byte2, byte3)

输出:

11100100 10111101 10100000

步骤 5:转为字节序列

bytes_list = [int(byte1, 2), int(byte2, 2), int(byte3, 2)]
print(bytes_list)
print(bytes(bytearray(bytes_list)))

输出:

[228, 189, 160]
b'\xe4\xbd\xa0'

步骤 6:直接用 Python 内置方法验证

print(list("你".encode("utf-8")))

输出:

[228, 189, 160]

验证无误。


三、为什么是 1110xxxx 10xxxxxx 10xxxxxx

UTF-8 的设计有其深层原因:

  1. 兼容 ASCII

    • ASCII 范围内的字符保持 0xxxxxxx 格式,完全不变。
    • 保证老系统、英文文档无需修改。
  2. 前缀位区分长度

    • 0, 110, 1110, 11110 分别标识 1~4 字节长度。
    • 解码时只需读首字节就能确定后续字节数。
  3. 后续字节以 10 开头

    • 避免二义性:解码器一眼就能区分“新字符的起始字节”和“延续字节”。
    • 保证解码唯一、无歧义。
  4. 存储效率与通用性平衡

    • 英文等常用字符仍是 1 字节。
    • 中文、日文、韩文等常用字符 3 字节。
    • Emoji 等稀有字符最多 4 字节。
    • 做到了效率与兼容的兼顾。

四、整体代码(封装版)

def char_to_utf8_bytes(ch):
    code_point = ord(ch)
    print(f"Unicode 码点: U+{code_point:X} ({code_point})")
    
    bits = bin(code_point)[2:].zfill(16)
    print(f"二进制: {bits}")
    
    # UTF-8 三字节模板填充
    byte1 = "1110" + bits[:4]
    byte2 = "10" + bits[4:10]
    byte3 = "10" + bits[10:]
    
    utf8_bytes = [int(byte1, 2), int(byte2, 2), int(byte3, 2)]
    return utf8_bytes

print(char_to_utf8_bytes("你"))
print(list("你".encode("utf-8")))

输出:

Unicode 码点: U+4F60 (20320)
二进制: 0100111101100000
[228, 189, 160]
[228, 189, 160]

五、如何快速确认文本需要几个字节

1. UTF-8 的编码范围划分如下:

Unicode 范围字节数模板格式
0x0000–0x007F10xxxxxxx
0x0080–0x07FF2110xxxxx 10xxxxxx
0x0800–0xFFFF31110xxxx 10xxxxxx 10xxxxxx
0x10000–0x10FFFF411110xxx 10xxxxxx 10xxxxxx 10xxxxxx

2. Python 实现:

def utf8_template(ch):
    code_point = ord(ch)
    if code_point <= 0x7F:
        return "1 字节: 0xxxxxxx"
    elif code_point <= 0x7FF:
        return "2 字节: 110xxxxx 10xxxxxx"
    elif code_point <= 0xFFFF:
        return "3 字节: 1110xxxx 10xxxxxx 10xxxxxx"
    elif code_point <= 0x10FFFF:
        return "4 字节: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx"
    else:
        return "超出 Unicode 范围"

print("你:", utf8_template("你"))
print("A:", utf8_template("A"))
print("€:", utf8_template("€"))   # 欧元符号 U+20AC
print("😀:", utf8_template("😀")) # emoji U+1F600

运行结果

: 3 字节: 1110xxxx 10xxxxxx 10xxxxxx
A: 1 字节: 0xxxxxxx
€: 3 字节: 1110xxxx 10xxxxxx 10xxxxxx
😀: 4 字节: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

六、总结

  • Unicode 是字符集,给每个字符分配唯一的代码点。
  • UTF-8 是编码方案,把 Unicode 码点转成字节序列。
  • "你" 的 Unicode 是 U+4F60,UTF-8 编码后是 [228, 189, 160]b'\xe4\xbd\xa0')。
  • UTF-8 的设计保证了 ASCII 兼容、解码唯一性,以及在效率和通用性上的平衡。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值