跳到主要内容
编码转换2026-05-226 分钟阅读

在线 Unicode 编码/解码工具:处理 Unicode 字符转换

什么是 Unicode

Unicode 是一个国际标准,为世界上几乎所有书写系统的每个字符分配唯一的编号(码点,Code Point)。它解决了早期编码(ASCII、GB2312、Shift-JIS)的兼容性问题——用在线 unicode encoder/decoder 可以在这些表示形式之间转换,如果需要二进制到文本的编码则用 base64 decoder。

Unicode 表示形式

形式示例说明
Unicode 码点U+4F60标准表示法
UTF-8\xe4\xbd\xa0变长编码(1-4 字节)
UTF-16\u4f60 / \uD83D\uDE00BMP 两字节;增平面用代理对
Unicode 转义序列\u4F60 或 \u{1F600}JavaScript/Java 中常见
HTML 实体你十进制实体(见 HTML 实体工具)
HTML 实体(十六进制)你十六进制实体

为什么需要 Unicode 编码/解码

  1. 跨语言兼容:不同编程语言间的字符传输
  2. JSON 安全:确保 JSON 中的特殊字符正确传输
  3. 数据库存储:处理数据库的字符编码问题
  4. URL 编码:URL 中包含非 ASCII 字符时的编码
  5. 日志分析:处理包含 Unicode 字符的日志数据
  6. 国际化开发:处理多语言文本的编码转换

UTF-8 vs UTF-16

特性UTF-8UTF-16
字节数1-4 字节2-4 字节
ASCII 兼容✅ 完全兼容❌ 不兼容
网络传输✅ 主流❌ 不常用
字节序无(无 BOM)有(大端/小端)
空间效率英文高效中文高效

如何使用在线工具

使用 ToolVault 工具匣 的 Unicode 编码/解码工具:

  1. 在左侧粘贴原始文本(可含中文、Emoji)
  2. 选择编码格式:
    • \uXXXX:UTF-16 码元转义;增平面字符自动拆成高低代理对(与 JSON.stringify 习惯一致)
    • \u{XXXXX}:按完整码点转义(ES6 风格,适合文档与现代 JS)
    • U+XXXX:标准码点列表,便于对照规范
    • \xHH:UTF-8 字节序列,便于对照抓包或文件十六进制
  3. 点「编码」得到转义串;点「解码」可混合识别上述形式(含代理对)
  4. 顶部同时显示三种长度:UTF-16 码元数、码点数、UTF-8 字节数
  5. 下方码点明细表列出每个字符的 U+…、UTF-16 转义与 UTF-8 字节

孤立代理项(只有 \uD83D 没有低代理)或非法 UTF-8 字节会被明确报错,而不是静默产出半截字符。

代码中的 Unicode 处理

JavaScript

// 字符 → Unicode 码点(按标量值迭代,勿用 charCodeAt 循环)
function toUnicode(str) {
  return Array.from(str).map((char) => {
    const cp = char.codePointAt(0);
    return 'U+' + cp.toString(16).toUpperCase().padStart(cp > 0xffff ? 5 : 4, '0');
  });
}

// Unicode 码点 → 字符
function fromUnicode(codePoint) {
  return String.fromCodePoint(parseInt(codePoint.replace(/^U\+/i, ''), 16));
}

// ES6 码点转义(emoji 不要写成非法的 \\u1F600)
function toBracedEscapes(str) {
  return Array.from(str)
    .map((char) => {
      const cp = char.codePointAt(0);
      return '\\u{' + cp.toString(16).toUpperCase() + '}';
    })
    .join('');
}

// JSON 风格:BMP 用 \\uXXXX,增平面拆成代理对
function toSurrogateEscapes(str) {
  return Array.from(str)
    .map((char) => {
      const cp = char.codePointAt(0);
      if (cp <= 0xffff) {
        return '\\u' + cp.toString(16).toUpperCase().padStart(4, '0');
      }
      const adj = cp - 0x10000;
      const hi = 0xd800 + (adj >> 10);
      const lo = 0xdc00 + (adj & 0x3ff);
      return (
        '\\u' + hi.toString(16).toUpperCase().padStart(4, '0') +
        '\\u' + lo.toString(16).toUpperCase().padStart(4, '0')
      );
    })
    .join('');
}

Python

import unicodedata

# 字符 → Unicode 码点
def to_unicode(char):
    return f"U+{ord(char):04X}"

# Unicode 码点 → 字符
def from_unicode(code_point):
    return chr(int(code_point.replace('U+', ''), 16))

# 获取字符信息
def char_info(char):
    return {
        'char': char,
        'code_point': f"U+{ord(char):04X}",
        'name': unicodedata.name(char, 'UNKNOWN'),
        'category': unicodedata.category(char)
    }

常见 Unicode 字符范围

范围内容示例
U+0000-U+007F基本拉丁字母A, b, 1, !
U+0080-U+00FF拉丁补充á, ñ, ü
U+0400-U+04FF西里尔字母А, Б, В
U+4E00-U+9FFFCJK 统一汉字中, 文, 字
U+3040-U+309F平假名あ, い, う
U+30A0-U+30FF片假名ア, イ, ウ
U+1F600-U+1F64FEmoji 表情😀, 😂, ❤️

三种编码形态与 UTF-8 为什么赢了 web

UTF-8(1-4 字节变长、ASCII 透明)、UTF-16(2 或 4 字节——JavaScript/Java/C# 字符串的内部形态)、UTF-32(定长 4 字节、罕见)。UTF-8 赢 web 因为对 ASCII 后向兼容(英文文本字节相同——90 年代互联网零迁移成本)且自同步(解析器从任意位置找到字符边界——损坏保持局部)。赢家的代价:CJK 每字符 3 字节(UTF-16 只要 2——中文存储贵 50%)、emoji 4 字节。工具含义:字节长、字符长、码点长是三个不同的数——「这字符串多长」必须先说单位;编码器会同时报这三种长度。

NFC 与 NFD:会失败的相等性

同一个视觉字符可以有多套码点序列:é 是预组合字符(U+00E9)或 e 加组合重音符(U+0065 U+0301)。渲染相同、字符串比较不同——「手输能用粘贴不行」的用户名 bug 和数据库重复条目的元凶。规范化到 NFC(web 的组合标准)修复比较;需要它的边界:用户输入对存储值、文件名比较、搜索。更深一层:Unicode 本身在加字符(emoji 版本),最新码点的「规范化相等」依赖版本——长寿系统钉住 Unicode 版本,否则库升级间相等性漂移。

码点、字符、字位簇的鸿沟

人类感知的「一个字」(带肤色的 emoji、韩文音节块、ZWJ 家庭表情)是字位簇——可能许多码点。下面每层都撒一点谎:码点把带修饰的 emoji 数成多个;UTF-16 码元把增平面的劈成两半(用户看到 6 个、字符串长度 11);字节再膨胀一轮。截断、光标移动、列对齐都要字位边界(JS 的 Intl.Segmenter)——数别的层就产出用户截图举报的「半个 emoji」。诚实的工具报长度时说单位;解码器显式展示码点——那是机器看到的,与眼睛看到的差距就是课。

代理对:JS 字符串长度的隐形坑

😀.length 在 JavaScript 里是 2,不是 1:引擎按 UTF-16 码元计数,增平面字符被编码成一对高低代理(如 \uD83D\uDE00)。用 charCodeAt 循环再拼 \uXXXX 时,若只处理一半代理,解码端会得到孤立代理或乱码。可靠做法是 codePointAt / for…of / Array.from,或让工具按标量值编码。反过来:合法 JSON 里常见成对的 \uD83D\uDE00;单独的 \uD83D 则应被拒绝——本站解码器对孤立代理会给出明确错误,而不是悄悄留下半个 emoji。

FAQ

为什么同一个汉字在不同编码中大小不同?

不同编码方式使用不同字节数:UTF-8 中汉字占 3 字节,UTF-16 中占 2 字节,GBK 中占 2 字节。这是编码方案设计的不同。

Unicode 和 UTF-8 有什么关系?

Unicode 是字符集标准(定义每个字符的编号)。UTF-8 是 Unicode 的一种编码实现(定义如何用字节表示这些编号)。UTF-8 是目前互联网最广泛使用的编码。

为什么有些中文字符显示为乱码?

常见原因:编码声明不匹配(文件用 UTF-8 保存但以 GBK 读取)、缺少字体支持、传输过程中编码转换错误。确保全链路使用统一的 UTF-8 编码;当字符显示异常时,可以用 unicode encoder/decoder 检查底层码点。

\uXXXX 和 \u{XXXXX} 该用哪一种?

需要与旧版 JSON / 大量现存转义兼容时,用 \uXXXX(emoji 会变成两个转义)。需要一眼看出真实码点、或写现代 JS 源码时,用 \u{1F600}。本站工具两种都能编、都能解;对照抓包或 hex dump 时再切到 UTF-8 \xHH。

排查注记

「这字符串多长」必须先说单位——字节长、码点长、UTF-16 码元长是三个不同的数,工具顶部同时报这三种长度、明细表逐字列出,正是这个论点的产品化。代理对一节用 😀 的 length 是 2 做锚点:引擎按码元计数,孤立代理在本站解码器里会明确报错、而不是悄悄留下半个 emoji——与码点/字位簇一节的结论呼应:数错层,就会产出用户截图举报的「半个 emoji」。NFC/NFD 一节标题就叫「会失败的相等性」:é 有两套码点序列,渲染相同、字符串比较不同,是「手输能用、粘贴不行」这类用户名 bug 的元凶。


感谢阅读这篇 ToolVault 工具匣 技术文章。更多开发者工具请访问 首页。