You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js解析含转义Unicode的JSON时Emoji显示乱码问题

Instagram导出JSON解析后Emoji乱码修复方案

问题背景

  • 从Instagram平台下载的JSON格式导出数据,在Node.js环境解析后存储至MongoDB时,出现转义Unicode字符无法在客户端正确渲染为对应Emoji的异常。

复现示例

待解析JSON文件中的title字段原始内容:

"title": "@mujenspirits is in the house!NEW York City \u00f0\u009f\u0097\u00bd\u00f0\u009f\u008d\u008e \nImperial Vintner Liquor Store"
  • 预期渲染效果:

@mujenspirits is in the house!NEW York City 🗽🍎
Imperial Vintner Liquor Store

  • 实际渲染乱码:

@mujenspirits is in the house!NEW York City 🗽ðŸŽ
Imperial Vintner Liquor Store

已尝试的无效方案

方案1:Uint8Array配合TextDecoder转码

该方案处理普通字符串时控制台验证有效,但配合JSON.parse使用仍存在显示异常,实现代码如下:

export default function parseJsonFile(filepath: string) {
  const value = fs.readFileSync(filepath)
  const converted = new Uint8Array(
    new Uint8Array(Array.prototype.map.call(value, (c) => c.charCodeAt(0)))
  )
  return JSON.parse(new TextDecoder().decode(converted))
}

方案2:Latin1转UTF8转码

根据社区建议,该类JSON生成逻辑存在缺陷:转义Unicode码点本质是按Latin1编码解码的UTF-8数据,尝试将加载内容先转码为latin1再解码为utf8,问题仍未解决,实现代码如下:

import buffer from 'buffer'

const value = fs.readFileSync(filepath)
const buffered = buffer.transcode(value, 'latin1', 'utf8')
return JSON.parse(buffered.toString())

问题根因

此前所有转码操作均作用于JSON原始文本层面,未命中问题发生的核心环节:

  • 示例中\u00f0\u009f\u0097\u00bd这类转义序列,实际对应Emoji🗽的UTF-8字节流(0xF0 0x9F 0x97 0xBD)。但JSON标准规定\uXXXX转义符代表UTF-16码元,JSON.parse执行时会直接将这类转义序列解析为U+00F0、U+009F等独立的Latin1区间字符,也就是最终看到的乱码。该错误发生在JSON解析执行阶段,对原始文件字节提前转码无法修正解析阶段生成的错误字符。

可行修复方案

方案1:解析后递归修复字符串(推荐,无侵入)

在JSON.parse完成后,遍历所有字符串类型字段,将错误解析的字符按Latin1编码取回字节,再用UTF-8解码即可得到正确内容,代码实现如下:

import fs from 'fs';

// 修复错误解析的乱码字符串
function fixMojibake(str: string): string {
  const buf = Buffer.from(str.split('').map(c => c.charCodeAt(0) & 0xff));
  return buf.toString('utf8');
}

// 递归遍历对象修复所有字符串字段
function deepFix(obj: any): any {
  if (typeof obj === 'string') {
    return fixMojibake(obj);
  }
  if (Array.isArray(obj)) {
    return obj.map(item => deepFix(item));
  }
  if (obj && typeof obj === 'object') {
    return Object.fromEntries(
      Object.entries(obj).map(([k, v]) => [k, deepFix(v)])
    );
  }
  return obj;
}

export default function parseJsonFile(filepath: string) {
  const rawContent = fs.readFileSync(filepath, 'utf8');
  const parsed = JSON.parse(rawContent);
  return deepFix(parsed);
}

验证说明:针对示例title字段,修复后可正确输出带🗽🍎Emoji的完整文本,存入MongoDB后客户端可正常渲染。

方案2:解析前预处理JSON文本(适合大文件场景)

如果JSON文件体积过大,递归遍历全量对象性能开销较高,可以在JSON.parse之前,将所有字节范围在0x80-0xff的\u00xx格式转义序列提前替换为原始字节,再统一按UTF-8解析,示例实现:

export default function parseJsonFile(filepath: string) {
  let rawContent = fs.readFileSync(filepath, 'latin1');
  // 替换所有UTF-8字节范围的\u转义序列为原始字节
  rawContent = rawContent.replace(/\\u00([89a-f][0-9a-f])/gi, (_, hex) => {
    return String.fromCharCode(parseInt(hex, 16));
  });
  return JSON.parse(Buffer.from(rawContent, 'latin1').toString('utf8'));
}

注意事项

  • 修复后存入MongoDB前无需额外转码,MongoDB默认使用UTF-8编码存储字符串,只要Node.js侧拿到正确的JS字符串,存储和客户端读取环节不会再出现乱码。
  • 读取文件阶段不要随意指定非latin1/binary的编码做前置转码,否则会提前破坏转义序列的原始值,导致后续修复失效。

内容的提问来源于stack exchange,提问作者bflemi3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 13:54:21