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

在Angular中实现deepDiff JSON对比结果高亮的问题求助

解决deepDiff JSON差异高亮失效问题

原代码核心问题分析

  1. 正则匹配错误:使用HTML转义符"替代原生双引号,导致无法匹配JSON字符串中的键名;未转义值中的正则特殊字符(如{、[、.),引发匹配异常。
  2. 差异类型逻辑混乱:
    • 修改类型(E)未区分文件:file1应高亮旧值diff.lhs,file2应高亮新值diff.rhs,原代码统一用diff.rhs导致file1匹配失败。
    • 新增(N)、删除(D)类型未过滤无效文件:新增项仅存在于file2,删除项仅存在于file1,原代码未做区分,产生无效匹配。
  3. 数组差异未处理:完全忽略A类型的数组差异,无法高亮数组内的变动项。
  4. 匹配精度不足:仅通过最后一个路径段+值匹配,遇到同名键且值相同时,会错误匹配无关节点。

修正后的实现代码

1. 更新差异对比函数(传递文件标识)

compareFiles() {
  if (this.file1Content && this.file2Content) {
    const differences = deepDiff.diff(this.file1Content.apis, this.file2Content.apis);

    if (differences) {
      this.comparisonResult = this.formatDifferences(differences);
      const filteredDifferences = differences.filter(diff => diff.path && !diff.path.some(p => p.key === 'index' && p.ignoreOrder));
      this.comparisonResult2 = filteredDifferences ? JSON.stringify(filteredDifferences, null, 2) : 'No differences found.';

      // 传递文件类型标识,让高亮函数知道处理的是哪份文件
      this.highlightedFile1Content = this.getHighlights(this.file1Content, differences, 'file1');
      this.highlightedFile2Content = this.getHighlights(this.file2Content, differences, 'file2');
    } 
  }
}

2. 修正高亮生成函数(含辅助工具函数)

// 辅助函数:转义正则特殊字符,避免匹配异常
escapeRegExp(str: string): string {
  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

getHighlights(jsonObject: any, differences: deepDiff.Diff<any, any>[], fileType: 'file1' | 'file2'): string {
  try {
    let jsonString = JSON.stringify(jsonObject, null, 2);
    const lines = jsonString.split('\n');

    differences.forEach(diff => {
      if (!diff.path || diff.path.length === 0) return;

      let targetValue: any;
      let shouldProcess = true;

      // 根据文件类型和差异类型,确定要高亮的目标值
      switch (diff.kind) {
        case 'E':
          targetValue = fileType === 'file1' ? diff.lhs : diff.rhs;
          break;
        case 'N':
          shouldProcess = fileType === 'file2'; // 新增项仅在file2中存在
          targetValue = diff.rhs;
          break;
        case 'D':
          shouldProcess = fileType === 'file1'; // 删除项仅在file1中存在
          targetValue = diff.lhs;
          break;
        case 'A':
          // 处理数组内部的子差异
          if (diff.item) {
            if (fileType === 'file1') {
              targetValue = (diff.item.kind === 'D' || diff.item.kind === 'E') ? diff.item.lhs : undefined;
            } else {
              targetValue = (diff.item.kind === 'N' || diff.item.kind === 'E') ? diff.item.rhs : undefined;
            }
          }
          break;
        default:
          shouldProcess = false;
      }

      if (!shouldProcess || targetValue === undefined) return;

      const targetValueStr = JSON.stringify(targetValue);
      const escapedValue = this.escapeRegExp(targetValueStr);
      const lastSegment = diff.path[diff.path.length - 1];
      // 构建键名的正则匹配串(区分数组索引和对象键)
      const keyStr = typeof lastSegment === 'number' ? `\\[${lastSegment}\\]` : `"${lastSegment}"`;
      // 根据路径层级计算缩进,确保只匹配对应层级的节点
      const indentLevel = diff.path.length - 1;
      const indent = '  '.repeat(indentLevel);
      const regex = new RegExp(`^${this.escapeRegExp(indent)}${keyStr}:\\s*${escapedValue}`);

      // 遍历行查找匹配,找到后立即退出避免重复替换
      for (let i = 0; i < lines.length; i++) {
        if (lines[i].match(regex)) {
          lines[i] = lines[i].replace(escapedValue, `<span class="highlight">${targetValueStr} DIFFERENCE FOUND!</span>`);
          break;
        }
      }
    });

    return lines.join('\n');
  } catch (e) {
    console.error("Error in getHighlights:", e);
    return JSON.stringify(jsonObject, null, 2);
  }
}

关键优化点说明

  • 文件类型区分:通过fileType参数精准控制不同文件应高亮的差异值,避免无效匹配。
  • 正则安全处理:用escapeRegExp转义特殊字符,防止正则语法错误。
  • 层级缩进匹配:根据路径层级计算缩进,确保只匹配对应层级的键值对,解决同名键误匹配问题。
  • 数组差异支持:处理A类型的数组内部差异,覆盖数组元素的新增、删除、修改场景。
  • 精准匹配退出:找到目标行后立即break,避免相同值的其他节点被错误替换。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 04:24:51