Skip to content

编码转换与中文乱码恢复

粘贴乱码即可自动还原原文。工具枚举 UTF-8、GBK、Big5、Shift_JIS、EUC-KR 等编码组合并按可信度排序,标出哪一条经过往返校验、能逐字复现。同时提供各编码下的字节对照与 hex 反解。免费在线,全程在浏览器内完成,内容不上传。

无追踪 浏览器中运行 免费
全部解码在你的浏览器本地完成——粘贴的内容不会离开这台设备。

乱码恢复

把乱码粘贴进来。工具会试遍所有可能的编码链并给结果排序——你不需要知道是哪种编码出的问题。

试试这些

最可能的原文

4 条候选
  1. 测试

    无损

    UTF-8 → GBK

  2. 娴嬭瘯

    无损

    Windows-1252 / Latin-1 → UTF-8

  3. 测试

    无损

    Windows-1252 / Latin-1 → GBK

  4. 测试

    无损

    Windows-1251 → GBK

编码转换与字节检视

一次看到同一段文本在所有常见编码下的字节——需要确认数据库或协议里究竟存了什么时很有用。

编码 字节数 十六进制
UTF-8 6 E4 B8 AD E6 96 87
GBK 4 D6 D0 CE C4
GB18030 4 D6 D0 CE C4
Big5 4 A4 A4 A4 E5
Shift_JIS 4 92 86 95 B6
EUC-KR 4 F1 E9 D9 FE

本页展示的每一条编码链都由页面运行的同一份引擎产出,「无损」徽章背后的往返校验在单元测试中针对已知字节序列做了断言。 — Go Tools Team · 2026年9月8日

由 Go Tools 工程团队构建并验证。

快速解答

什么编码会把「测试」变成「娴嬭瘯」?

UTF-8 → GBK UTF-8 的字节被当成 GBK 读。6 个 UTF-8 字节(E6 B5 8B E8 AF 95)被重新切成了 3 个 GBK 字符。

什么会把「测试」变成「测试」?

UTF-8 → Windows-1252 同样这串 UTF-8 字节,被当成 Windows-1252 读。因为它是单字节编码,6 个字节各自变成一个字符。

含有 � 的乱码还能救吗?

不可恢复 救不了。那些字节在解码时已被丢弃。尽量从周围文字还原,其余部分只能回源数据取。

一个汉字占几个字节?

3 与 2 字节 UTF-8 里 3 个,GBK 与 Big5 里 2 个。按字节而非字符来定字段长度时,这个差别是截断故障的常见来源。

什么是乱码

乱码是用一种字符编码写出、却用另一种字符编码读入的结果。字节本身完好无损,错的只是解释方式。这个区别正是还原之所以可能的全部原因:只要判断出是哪种编码写的、被哪种编码误读,就能把这个错误倒着执行一遍,拿回原文。

这个词的日文写法是「文字化け」,大意是「字符变形」。它之所以成为通用术语,是因为在 Unicode 普及之前,日文计算环境里这个问题极其普遍。中日韩文本比拉丁文本更容易中招,原因是结构性的:这些语言必须用多字节编码,而不同的多字节编码对「字节该怎么分组」意见不一致。拉丁文本大多落在 ASCII 范围内,而所有编码在 ASCII 上的约定都是一样的。

还原只在一种情况下失败:解码器遇到在自己编码里没有定义的字节时,不会保留它们,而是替换成 U+FFFD 后丢弃。这些字符永久丢失,其余一切都是可逆的。

// The mistake, in three lines of JavaScript
const bytes = new TextEncoder().encode('测试');   // UTF-8: E6 B5 8B E8 AF 95
new TextDecoder('gbk').decode(bytes);            // '娴嬭瘯'  ← mojibake
new TextDecoder('windows-1252').decode(bytes);   // '测试'  ← same bytes, other mistake

这个工具能做什么

不需要知道是什么编码

粘贴乱码,工具替你枚举编码链。UTF-8、GBK、GB18030、Big5、Shift_JIS、EUC-KR、Windows-1252、Windows-1251 之间「写入编码 × 读出编码」的每一种组合都会试一遍。

无损结果是校验出来的,不是猜的

只有当还原结果沿同一条链倒推能逐字复现你的输入时,才会标为无损。这是确定性检查——只给一个排序,你就无从判断哪些结果值得相信。

编码链是摆出来的,不是藏起来的

每条候选都注明是哪种编码写的、被哪种编码误读。这才是修复上游所需要的信息,否则下周还得对着新数据再修一遍同样的字符串。

救不回来时如实说

输入里若已含替换符,工具会直接说明,并把所有候选标为部分还原。解码时被销毁的信息不会回来,假装它能回来只会浪费一个下午。

一次看全所有编码的字节

把同一段文本在各编码下的十六进制字节并排列出,也支持把 hex 反向解成文字。核对字段长度、读抓包结果、检查 BLOB 内容时都用得上。

内容不出浏览器

解码用的是浏览器自带的 TextDecoder,不上传、不存储、不改写 URL——需要还原的乱码通常直接来自生产环境,这一点很关键。

实例解析

UTF-8 被当作 GBK 读 —— 最经典的一种

娴嬭瘯
测试

这两个汉字本来以 UTF-8 正确存储(字节为 E6 B5 8B E8 AF 95),随后某个程序把这 6 个字节当成 GBK 来读。GBK 是两字节一组,于是 6 个字节被切成 3 个字符,字数都对不上了。老版 Windows 程序打开 UTF-8 文件、或者数据库连接串写了 characterEncoding=gbk 而数据实为 UTF-8,出来的就是这个样子。

UTF-8 被当作 Windows-1252 读 —— 西欧变体

测试
测试

同样的字节,另一种误读。Windows-1252 是单字节编码,所以 6 个 UTF-8 字节各自变成了一个字符。拉丁语系遇到的多是这一种:café 变成 café,naïve 变成 naïve。特征是成对出现的 Ã、Â、â 和莫名其妙的标点符号。

手头只有十六进制字节

B2 E2 CA D4
测试

有时候面对的不是乱码文本,而是抓包结果或者 BLOB 字段里的一段十六进制。把 hex 粘进第二个区块、选好编码即可。B2 E2 CA D4 在 GBK 里就是「测试」——同样两个字在 UTF-8 下要占 6 个字节(E6 B5 8B E8 AF 95),而在 Windows-1252 里根本无法表示。

救不回来的乱码长什么样

鏁版嵁搴�
(只能部分还原)

「数据库」以 UTF-8 写出、被当成 GBK 读,但最后一组字节在 GBK 里没有定义,解码器把它替换成了 U+FFFD。那个字节已经没了。工具会如实标出这种情况,而不是硬猜一个像样的答案——前面的「数据」仍能还原,最后一个字则必须回到源数据去取。

使用方法

  1. 1

    粘贴乱码

    直接粘进来,不用先判断编码。一小段就够,十几个字符通常足以锁定编码链。

  2. 2

    看首条结果和它的徽章

    无损=沿同一条链倒推能逐字复现你的输入;部分=对不上,只能当线索。

  3. 3

    看清编码链

    每条候选都标出原文的真实编码与误读它的编码。这告诉你上游该改哪里,而不只是这段文字原本是什么。

  4. 4

    需要时查字节

    第二个区块能把任意文本按各编码列出字节,也能把 hex 反解成文字。核对字段长度、排查报文时用它。

越弄越糟的几种做法

对本来就没坏的文本做转换

文本显示正常却照样转一遍,反而会亲手制造出想要避免的乱码。先确认当前状态,另外注意区分:缺字体渲染成方块(□□□),编码问题渲染成别的字。

✗ 错误
iconv -f UTF-8 -t GBK correct.txt > broken.txt
✓ 正确
# 先确认当前编码
file -I correct.txt   # charset=utf-8 → 无需转换

声明一个数据并不具备的字符集

改 MySQL 列的声明字符集,并不会重新编码里面已有的字节。把 latin1 的数据声明成 utf8,服务器会交出并非合法 UTF-8 的字节,驱动随即用 U+FFFD 替换——数据就此被销毁。

✗ 错误
ALTER TABLE t MODIFY c VARCHAR(255) CHARACTER SET utf8mb4;
✓ 正确
-- 先过一次二进制类型,让字节被保留而不是被重新解释
ALTER TABLE t MODIFY c VARBINARY(255);
ALTER TABLE t MODIFY c VARCHAR(255) CHARACTER SET utf8mb4;

把「部分还原」当成答案

标为部分的候选没有通过往返校验。它值得跟进,但不是一个可以直接写回数据库的答案。如果一条无损结果都没有,多半是输入本身已经丢了信息,应该回到源字节去处理。

✗ 错误
// 不管徽章说什么,取第一条
db.update(row.id, candidates[0].text);
✓ 正确
// 只写回通过往返校验的结果
if (candidates[0].lossless) db.update(row.id, candidates[0].text);

沿用 Python 2 的习惯

在 Python 3 里对已经是 bytes 的东西调 encode、或对已经是 str 的东西调 decode 会直接抛异常,而不是像 Python 2 那样静默地绕一圈 ASCII。在边界处解码一次,之后一律按文本处理。

✗ 错误
text = raw.decode('utf-8').encode('gbk').decode('utf-8')
✓ 正确
# 在边界处解码一次,用文件真正使用的编码
with open(path, encoding='gbk') as f:
    text = f.read()

什么时候需要它

数据库迁移之后全是乱码
老 MySQL 表声明为 latin1、实际存的却是 UTF-8 字节,这是最常见的单一来源。先把一条乱码记录粘到本页确认真实的编码链,再去写 ALTER TABLE——方向搞反会把一个可恢复的问题变成永久性损坏。
CSV 用 Excel 打开是乱码
Windows 版 Excel 至今对没有 BOM 的 CSV 按系统代码页解读,所以 UTF-8 导出的文件打开就是乱码。在本页确认编码链后,导出时加 BOM,或者用「数据 → 从文本」向导显式指定编码。
老服务写出来的日志
按 GBK 或 Shift_JIS 开发的程序,日志就是那个编码写的,而现代日志采集端一律按 UTF-8 读。粘一行进来即可还原——而且因为内容不上传,可以直接拿生产日志来做。
压缩包里的文件名坏了
ZIP 格式没有编码字段,中文或日文 Windows 上打的包,文件名是 GBK / Shift_JIS,Unix 工具按 UTF-8 读就成了乱码。改名之前先在这里还原出真实文件名。
估算数据库字段长度
字节视图把同一段文本在各编码下的长度并排列出。一个汉字在 UTF-8 里占 3 字节、在 GBK 里占 2 字节——这个差别正是把 VARCHAR(50) 变成截断故障的那类原因。

乱码是怎么产生的

字节留下了,含义没有
编码是把字符映射成字节,解码是把字节映射回字符。乱码就是用错了映射表的一次解码。字节从头到尾没被破坏过,所以把错误的解码倒着走一遍就能精确拿回原文——前提是那次错误的解码没有丢掉任何东西。
为什么中日韩文本受害最深
ASCII 占据 0x00–0x7F,所有常见编码在这一段的约定完全一致,所以英文文本能毫发无损地穿过去。中日韩文字必须用多字节序列,而各编码对「怎么分组」的规定不同:UTF-8 一个汉字 3 字节,GBK 是 2 字节。把 UTF-8 字节喂给 GBK 解码器,分组就错位了,于是得到数量不同、内容也不同的一串字。
往返校验
对每条候选链,工具用第一个编码把还原结果重新编码,再用第二个编码解码。若能逐字复现输入,说明这条链解释了每一个字符,该候选标记为无损。校验不通过的候选仍然会列出,因为部分还原往往已经足以看懂原文,即使无法完整复现。
编码表从哪来
解码方向直接用浏览器的 TextDecoder。反方向要麻烦些——TextEncoder 只支持 UTF-8,所以工具通过遍历字节空间、逐个询问解码器的方式反推出编码表。这样映射永远与浏览器自身行为一致,也不必向你的设备下发任何映射数据。
排序启发式,以及它的边界
在往返校验之外,候选还会按可读性打分:常用汉字(GBK 首字节落在 0xB0–0xF7 那一段)占比加分,替换符、半角片假名、控制字符扣分。半角片假名是 Shift_JIS 误读的强特征,因为正常日文文本几乎不用它。这是启发式,只用于打破平局,不负责判定真相。

怎样避免再次发生

修源头,不只是修那串字
每条候选下面标出的编码链会告诉你是哪个环节配错了。只修好文本却不改连接串编码、文件读取方式或导出设置,明天面对新数据还得再修一次。
整文件转换前先确认方向
先拿有代表性的一行到本页跑一遍。 方向反了会产生替换符,而这一步与最初那次误读不同——它不可逆。
所有地方都显式写死编码
数据库连接串编码、HTTP Content-Type、文件打开调用、CSV 导出选项。每一处依赖「系统默认编码」的地方,都是同一个 bug 换台机器就会复发的地方。
MySQL 里用 utf8mb4 而不是 utf8
MySQL 的 utf8 每个字符最多存 3 字节,emoji 和部分生僻汉字会被静默截断。utf8mb4 才是真正的 UTF-8。这类损坏与乱码不同,本工具救不了——那些字节是真的没了。
在验证修复之前留住原始字节
动手转换前先备份。只要原始字节还在,任何一次错误的解码都是可逆的;一旦被替换符覆盖写回,本页和其他任何工具都无能为力。

常见问题

中文显示成乱码,怎么恢复?
把乱码粘贴到本页顶部的输入框即可。工具会枚举所有可能的编码链并给结果排序,你不需要自己判断是什么编码。绝大多数情况下答案是两种:UTF-8 被当成 GBK 读(会看到「娴嬭瘯」这类汉字),或者 UTF-8 被当成 Windows-1252 读(会看到「测试」这类字符)。这两种都能精确还原。
「无损」徽章到底校验了什么?
它把还原过程倒着跑了一遍:用编码链的第一个编码把还原结果重新编成字节,再用第二个编码解码,如果结果与你粘贴的输入逐字相同,说明这条链能完整解释每一个字符,徽章才显示为无损。这是确定性的往返校验,而不是相似度打分——所以无损结果的可靠程度,和一个排序靠前的猜测完全不是一回事。
为什么有些乱码永远救不回来?
因为损坏发生在你看到它之前。解码器遇到在自己编码里没有定义的字节序列时,不会保留原字节,而是替换成 U+FFFD(显示为 �)并丢弃。这一步是有损且不可逆的。如果你的文本里含有 �,那几个字符无论用什么工具都找不回来了。本页会直接告诉你这一点,而不是生成一个看起来很有把握的猜测。
GBK、GB2312 和 GB18030 有什么区别?
同一族的三代标准,后一代是前一代的超集。GB2312(1980)收录 6,763 个简体汉字,够日常使用;GBK(1995)扩到约 21,000 字,包含繁体字形;GB18030(2000 年起为国家强制标准)覆盖全部 Unicode。做乱码还原时基本都该选 GBK,因为造成问题的那些老软件当年就是照 GBK 写的。
ISO-8859-1 和 Windows-1252 是一回事吗?
标准上不是,但在浏览器里是。浏览器实现的 WHATWG Encoding Standard 明确把 iso-8859-1latin1 都当作 windows-1252 的别名。两者只在 0x80–0x9F 这一段不同:真正的 ISO-8859-1 那里是控制字符,Windows-1252 那里是破折号、弯引号这类可打印符号。而乱码里冒出来的恰恰就是这些可打印符号,所以 Windows-1252 更有用,本工具把两个名字合并为一项。
粘贴的内容会上传吗?
不会。所有解码都用浏览器自带的 TextDecoder 在本地完成,不发网络请求、不写入存储、也不改写 URL。这一点对本工具比对其他工具更重要:需要还原的乱码,来源几乎总是生产日志、客户记录或数据库导出——正是最不该粘进服务端工具的那类内容。
能不能转换整个文件,而不只是一小段?
本页处理粘贴进来的文本。整个文件用命令行更合适:macOS 与 Linux 上是 iconv -f GBK -t UTF-8 input.txt > output.txt,PowerShell 里是 Get-Content -Encoding Default in.txt | Set-Content -Encoding UTF8 out.txt先把有代表性的一行粘到本页确认编码链,再去写命令——方向搞反的话,一行的小问题会变成一千行的大问题。
为什么给出好几个候选,而不是直接给一个答案?
因为确实可能有多条链都能解出像样的文本,工具不打算把这件事瞒着你。候选的排序是:先把往返自洽(无损)的排在前面,其余再按可读性启发式排序——常用汉字加分,替换符、半角片假名、控制字符扣分。启发式只用来打破平局,不负责判定真相。两个候选都说得通时,每条下面标出的编码链能告诉你哪一条与你的数据来源对得上。