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

调用API返回含重复键的JSON,如何将重复键转换为数组?

解决JSON重复键转数组的问题

为啥reviver拿不到所有重复键?

标准JSON规范里不允许对象存在重复键,JS自带的JSON.parse解析时会直接覆盖前面的重复键值对,只保留最后一个,所以你的reviver函数只能拿到最后一个line的值——这不是bug,是规范要求的行为。

怎么处理这种非标准JSON?

要把重复键转成数组,得先预处理JSON字符串,或者写个自定义解析器,下面给两种实用方案:

方法一:正则预处理字符串(适合简单结构)

用正则匹配重复键值对,直接把它们合并成数组格式:

const rawJson = '{"address":{"city":"Toronto", "line":"ln1","line":"ln2","line":"ln3"}}';
const tempMap = {};

// 第一步:把重复键的第一个值改成数组开头
let processed = rawJson.replace(/"([^"]+)":\s*"([^"]+)"(?=\s*,"\1":)/g, (match, key, val) => {
  if (!tempMap[key]) {
    tempMap[key] = true;
    return `"${key}": ["${val}"`;
  }
  return `,"${val}"`;
});

// 第二步:给数组补上结尾的]
processed = processed.replace(/"([^"]+)":\s*\["([^"]+)"(.*?)(?=\s*(}|,))/g, (match, key) => {
  tempMap[key] = false;
  return `${match}]`;
});

// 解析处理后的标准JSON
const result = JSON.parse(processed);
console.log(result);

方法二:自定义解析器(复杂场景适用)

如果JSON嵌套深、包含转义字符等特殊情况,正则搞不定,就自己写个逐字符解析的函数,遇到重复键就自动转成数组:

function parseDuplicateKeyJson(jsonStr) {
  let idx = 0;
  const len = jsonStr.length;

  // 跳过空格
  const skipWs = () => {
    while (idx < len && /\s/.test(jsonStr[idx])) idx++;
  };

  // 解析字符串(处理转义字符)
  const parseStr = () => {
    idx++; // 跳过开头的"
    let str = '';
    while (idx < len && jsonStr[idx] !== '"') {
      if (jsonStr[idx] === '\\') {
        idx++;
        str += jsonStr[idx];
      }
      str += jsonStr[idx++];
    }
    idx++; // 跳过结尾的"
    return str;
  };

  // 解析对象(核心处理重复键)
  const parseObj = () => {
    idx++; // 跳过{
    const obj = {};
    skipWs();
    while (idx < len && jsonStr[idx] !== '}') {
      const key = parseStr();
      skipWs();
      idx++; // 跳过:
      const val = parseValue();
      skipWs();

      // 重复键处理:已存在则转数组,不存在直接赋值
      if (obj[key]) {
        if (!Array.isArray(obj[key])) obj[key] = [obj[key]];
        obj[key].push(val);
      } else {
        obj[key] = val;
      }

      if (jsonStr[idx] === ',') idx++; // 跳过分隔符,
      skipWs();
    }
    idx++; // 跳过}
    return obj;
  };

  // 解析数组、布尔值、null、数字的逻辑(和标准解析一致)
  const parseArr = () => {
    idx++;
    const arr = [];
    skipWs();
    while (idx < len && jsonStr[idx] !== ']') {
      arr.push(parseValue());
      if (jsonStr[idx] === ',') idx++;
      skipWs();
    }
    idx++;
    return arr;
  };

  const parseBool = () => {
    const boolStr = jsonStr.slice(idx, idx + 4);
    idx += boolStr.length;
    return boolStr === 'true';
  };

  const parseNull = () => {
    idx += 4;
    return null;
  };

  const parseNum = () => {
    let numStr = '';
    while (idx < len && /[0-9.e+-]/.test(jsonStr[idx])) numStr += jsonStr[idx++];
    return Number(numStr);
  };

  // 统一调度解析逻辑
  const parseValue = () => {
    skipWs();
    const char = jsonStr[idx];
    if (char === '{') return parseObj();
    if (char === '[') return parseArr();
    if (char === '"') return parseStr();
    if (char === 't' || char === 'f') return parseBool();
    if (char === 'n') return parseNull();
    return parseNum();
  };

  return parseValue();
}

// 使用示例
const rawJson = '{"address":{"city":"Toronto", "line":"ln1","line":"ln2","line":"ln3"}}';
const result = parseDuplicateKeyJson(rawJson);
console.log(result);

额外提醒

这种带重复键的JSON属于非标准格式,优先建议和供应商沟通,让他们改成标准JSON返回(比如直接把line做成数组),这才是最稳妥的解决办法。自己处理的话,要注意覆盖转义字符、嵌套结构等边界场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 12:40:35