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

使用jq处理连续eventId的JSON消息合并(浮点数精度异常)

合并连续eventId的消息字段

需求说明

给定如下JSON结构,当eventId为连续值时合并对应message字段;但若message以# Time:开头,即使eventId连续也需分隔处理。

原始JSON结构

{
    "events": [
        {
            "message": "# Time: 1",
            "eventId": "38636469249093328935961608873790523617989208925384015872"
        },
        {
            "message": ", 2, 3",
            "eventId": "38636469249093328935961608873790523617989208925384015873"
        },
        {
            "message": "# Time: 11",
            "eventId": "38636469249093328935961608873790523617989208925384015875"
        },
        {
            "message": "# Time: 12",
            "eventId": "38636469249093328935961608873790523617989208925384015876"
        },
        {
            "message": "# Time: A",
            "eventId": "1"
        },
        {
            "message": ", B, C",
            "eventId": "2"
        },
        {
            "message": "# Time: C",
            "eventId": "3"
        },
        {
            "message": "# Time: D",
            "eventId": "5"
        }
    ]
}

期望输出

[
  {
    "message": "# Time: 1, 2, 3"
  },
  {
    "message": "# Time: 11"
  },
  {
    "message": "# Time: 12"
  },
  {
    "message": "# Time: A , B, C"
  },
  {
    "message": "# Time: C"
  },
  {
    "message": "# Time: D"
  }
]

尝试过程及问题

1. 初始jq命令(浮点数精度问题)

使用以下命令时,因大eventId转为浮点数丢失精度,导致连续eventId判断失效,未正确合并消息:

jq -r '.events 
| reduce .[1:][] as $i (.[:1];
    if ((.[-1].eventId | tonumber + 1 | tostring) != $i.eventId) or ($i.message | startswith("# Time:")) then
        . += [$i]
    else
        .[-1].message += " " + $i.message
    end
) 
| del(.[].eventId)
'

执行结果:

[
  {
    "message": "# Time: 1"
  },
  {
    "message": ", 2, 3"
  },
  {
    "message": "# Time: 11"
  },
  {
    "message": "# Time: 12"
  },
  {
    "message": "# Time: A , B, C"
  },
  {
    "message": "# Time: C"
  },
  {
    "message": "# Time: D"
  }
]

2. 自定义字符串加法函数(逻辑错误)

尝试自定义字符串加法函数处理大数字,但函数逻辑有误,导致小eventId的连续判断也失效:

jq '
# Function to add one to a large number represented as a string
def add_one(num):
  (num | split("") | reverse | map(tonumber)) as $digits
  | reduce range(0; length) as $i ([];
      . + if $i == 0 or .[-1] == 10 then
            [($digits[$i] + 1) % 10]
         else
            [$digits[$i]]
         end
    )
  | reverse | map(tostring) | join("");

# Process events and check continuity
.events 
| map(.eventId |= tostring) # Ensure all eventIds are strings
| reduce .[1:][] as $i (.[:1];
    if (add_one(.[-1].eventId) != $i.eventId) or ($i.message | startswith("# Time:")) then
        . += [$i]
    else
        .[-1].message += " " + $i.message
    end
)
| del(.[].eventId)
'

执行结果:

[
  {
    "message": "# Time: 1"
  },
  {
    "message": ", 2, 3"
  },
  {
    "message": "# Time: 11"
  },
  {
    "message": "# Time: 12"
  },
  {
    "message": "# Time: A"
  },
  {
    "message": ", B, C"
  },
  {
    "message": "# Time: C"
  },
  {
    "message": "# Time: D"
  }
]

当前使用jq 1.7.1版本,需在不使用gojq的前提下解决问题。


解决方案

问题出在两个地方:一是自定义的add_one函数逻辑错误(未正确处理进位),二是判断条件的顺序需要调整(先判断当前message是否以# Time:开头,再判断eventId连续性)。

修正后的jq命令如下:

jq '
# 正确实现字符串数字加1的函数
def add_one(s):
  s | split("") | reverse | map(tonumber)
  | reduce .[] as $d ([[], false];
      if .[1] then
          if $d == 9 then
              [[0] + .[0], true]
          else
              [[$d + 1] + .[0], false]
          end
      else
          if $d == 9 then
              [[0] + .[0], true]
          else
              [[$d + 1] + .[0], false]
          end
      end
  )
  | if .[1] then [1] + .[0] else .[0] end
  | map(tostring) | join("");

.events
| reduce .[] as $item ([];
    if length == 0 then
        # 初始化第一个元素
        [$item]
    else
        # 先判断当前消息是否是新的Time条目
        if $item.message | startswith("# Time:") then
            . += [$item]
        else
            # 再判断eventId是否连续
            if add_one(.[-1].eventId) == $item.eventId then
                .[-1].message += " " + $item.message
            else
                . += [$item]
            end
        end
    end
)
| del(.[].eventId)
'

说明

  1. 修正add_one函数:正确处理数字进位,包括所有位都是9的极端情况(如"999"加1变为"1000")。
  2. 调整判断顺序:先检查当前message是否以# Time:开头,若是则直接作为新条目;否则再判断eventId是否连续,连续则合并消息。
  3. 初始化逻辑优化:从空数组开始处理,避免原逻辑中.[:1]的局限性。

执行该命令后,输出与期望结果完全一致。


内容的提问来源于stack exchange,提问作者P.Lonnie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 22:04:54