转义与反转义

处理 JSON、JavaScript、HTML 和 URL

正在加载工具…

关于 字符串转义与反转义

字符串转义与反转义工具会重写一个值,让 JSON 解析器、JavaScript 编译器、HTML 解析器或 URL 解析器把它当作数据而不是语法来读。选定四种目标上下文之一,再选转义或反转义,结果面板会清楚呈现哪些字符被改写、哪些被原样保留。

转义不是一个只有唯一正确答案的操作。同一个字符串,在 JSON 里要在双引号前加反斜杠,在 JavaScript 字面量里要在单引号前加反斜杠,在 HTML 里要写成实体引用,在查询串分量里则要百分号编码。对其中一种正确的结果,放到另外三种里就是错的,有时还是危险的错。要回答的从来不是「怎么转义」,而是「这个值会先被哪个解析器读到」。

如何使用这个开发者工具

  1. 先想清楚这个值最终落在哪里:JSON 字符串内部、JavaScript 字符串字面量内部、HTML 文本或属性内部,还是 URL 的某一个分量里。
  2. 在规则列表中选择对应的上下文,并把模式切换到「转义」或「反转义」。
  3. 粘贴一个有代表性的值,而不是整份文档,然后执行转换。
  4. 在分隔符处逐字符对照两个面板。引号、反斜杠、尖括号、百分号和换行,正是四种上下文唯一有分歧的地方。
  5. 复制结果,并交给真正的解析器验证:把 JSON 结果丢进 JSON 格式化工具,或把 URL 结果放进一次真实请求里,而不是只靠肉眼确认。

实例:同一个值,四个都正确的答案

这个值里带齐了四种上下文会产生分歧的字符:单引号、双引号、反斜杠和换行。逐一套用四条规则,差异会一眼可辨。

输入
O'Neill & Sons said "ok"
path: C:\tmp\a b.txt
逐条规则转义
JSON 字符串
O'Neill & Sons said \"ok\"\npath: C:\\tmp\\a b.txt

JavaScript 字符串
O\'Neill & Sons said \"ok\"\npath: C:\\tmp\\a b.txt

HTML 实体
O'Neill & Sons said "ok"
path: C:\tmp\a b.txt

URL 组件
O'Neill%20%26%20Sons%20said%20%22ok%22%0Apath%3A%20C%3A%5Ctmp%5Ca%20b.txt

有三处值得停下来看。JSON 不动单引号,JavaScript 则要转义它。HTML 不动反斜杠和真实换行,因为这两者对 HTML 解析器没有任何含义。URL 规则同样放过单引号——这正是「百分号编码过的值」依然不能直接塞进单引号属性里的原因。

同一个字符在四种目标上下文中的写法

横向读一行,就能明白为什么按某个上下文转义过的值,在另一个上下文里等于没转义。「保持原样」表示该字符被逐字节原样复制。

字符JSON 字符串JavaScript 字符串HTML 实体URL 组件
双引号\"\""%22
单引号保持原样\''保持原样
反斜杠\\\\保持原样%5C
换行\n\n保持原样,仍是真实换行%0A
和号 &保持原样保持原样&%26
小于号 <保持原样保持原样&lt;%3C
NUL,U+0000\u0000保留为裸控制字符保留为裸控制字符%00
任意非 ASCII 字符保持原样保持原样保持原样中 编码为 %E4%B8%AD

常见问题排查

输出里的反斜杠比预期多了一倍。

成因 这个值已经被转义过一次。再转义一次,第一轮引入的反斜杠自身也会被转义,于是 JSON 片段里的 \"ok\" 变成了 \\\"ok\\\"。

解决办法 切到「反转义」执行一次,确认输入面板里出现的是干净的原始值,再从这里转义一次。如果需要连续反转义两次,说明上游确实做了双重编码,那才是要修的缺陷。

值已经转义了,页面还是坏的。

成因 按错误的上下文转义了。URL 编码不会碰单引号,所以一个百分号编码后的值放进单引号包裹的 HTML 属性里,照样会提前闭合属性。

解决办法 按「最内层解析器优先」的顺序转义,再逐层向外。不要因为输出看起来「像编码过了」,就用一种上下文的规则去顶替另一种。

值里带 emoji 或其他非 BMP 字符时,URL 转义失败。

成因 U+FFFF 以上的字符以代理对形式存储。如果这个值先被 slice 或 substring 按固定长度裁过,代理对可能被切断,而百分号编码拒绝孤立的代理项。

解决办法 按码点边界裁剪字符串,例如先展开成数组再切,而不要按 UTF-16 下标切。注意 JSON 规则在这里不会报错——它会把孤立半个代理项输出成 \ud83d——所以只测 JSON 路径的话,同一个缺陷会一直隐身。

JavaScript 反转义把一个 Windows 路径变成了制表符和换行。

成因 JavaScript 规则先展开换行、回车、制表符这三种双字符序列,之后才合并双反斜杠,于是 C:\\tmp\\new.txt 里第二个反斜杠和后面的字母配成了一对。

解决办法 凡是含双反斜杠的内容都改用 JSON 规则,JSON 解析器处理顺序是正确的。JavaScript 规则只留给「含引号但不含转义路径分隔符」的短字面量。

适合用这个工具的场景

  • 把多行片段——证书正文、日志摘录、Shell 脚本——折进 JSON 的一个字符串字段里。
  • 排查查询串参数为什么在服务端被截断:看清哪些字符压根没做百分号编码。
  • 从日志行里读出被过度转义的值,也就是 JSON 文档被序列化进了另一个 JSON 字符串的情况。
  • 把一段用户提交的文本变成 HTML 安全的内容,用于测试夹具或快照文件。

应该换用别的工具的场景

  • 让不可信输入变安全。转义改变的是表示形式,不是含义;按 HTML 转义过的字符串内容依然是它自己,后面某个模板若把它当标记插入,前面的功夫就白做了。
  • 编码一整条 URL。URL 规则针对的是单个分量,因此会把完整地址所需的斜杠、冒号和问号一并编码。整条地址请用 URL 编码与解码工具。
  • 对整份 HTML 文档做批量实体处理。那是 HTML 实体编码与解码工具的活,它覆盖的命名实体也远多于这条规则改写的五个字符。

隐私与数据处理

所有转换都在当前浏览器标签页内完成,用的是平台自带的 JSON.stringify、encodeURIComponent 和 DOM 接口。内容不上传,关闭标签页即丢弃。真正需要转义的值往往恰好是敏感的那些——连接串、带签名的 URL、请求体里的令牌——请先替换成形状相同的占位符。本地处理只能保证值不进我们的服务器,挡不住浏览器扩展。

相关开发者工具

常见问题

为什么 JSON 模式不转义单引号?

JSON 语法只要求转义双引号、反斜杠以及 U+0020 以下的控制字符。单引号在 JSON 字符串里没有任何语法含义,所以原样保留。JavaScript 模式转义它,是因为 JavaScript 字面量可以用单引号作定界符。

转义等于消毒吗?

不等于。转义保证解析器把你的值当作一个不可分割的记号来读;消毒决定哪些内容根本不允许出现。一条按 HTML 转义过的评论会以纯文本渲染,但只要系统另一处把同样的内容当标记渲染,它照样不安全。

为什么 HTML 结果里还留着换行?

HTML 实体转义只改写五个具有结构含义的字符。换行对 HTML 解析器来说只是普通空白,会在渲染时被折叠,而不是被删除。想让换行可见,请把值放进 pre 元素,或把 white-space 设为 pre-wrap。

转义会改变值的含义吗?

只要严格做一次往返就不会。在这里的每种上下文中,用同一条规则先转义再反转义都能还原原始字符串,只有一个例外值得记住:JavaScript 规则对双反斜杠是有损的,因此 Windows 路径无法往返。

要放进 Shell 命令或正则表达式的值该用哪条规则?

这四条都不合适。Shell 有自己的元字符和引用规则,正则表达式又是另一套。正则请在正则表达式测试器里构造;Shell 参数请用所在语言的参数数组接口传递,不要用字符串拼接。

为什么建议粘贴一小段代表值,而不是整个文件?

转义是上下文敏感的,而一个文件通常横跨多种上下文:JSON 文档里套着 HTML 片段,HTML 片段里又嵌着 URL。把整个文件当一个单位转义,等于对其中大部分内容套错了规则。只转换那个真正跨越边界的值,其余原样保留。