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

Golang解析含JSON数据的CSV文件问题求助

解决方案

一、修正结构体定义

首先你的结构体JSON标签存在错误(中文引号、字段映射不匹配),先修正为合法格式:

type ItemRatings struct {
    RestaurantId int       `json:"restaurant_id"` // 对应CSV的RestaurantId字段
    Date         string    `json:"date"`          // 对应CSV的Date字段
    ItemData     []ItemData `json:"item_data"`
}

type ItemData struct {
    ItemID          int    `json:"item_id"`
    ItemName        string `json:"item_name"`
    CurrentDayCount int    `json:"current_day_count"`
    CurrentDaySum   int    `json:"current_day_sum"`
    MTDCount        int    `json:"mtd_count"`
    MTDSum          int    `json:"mtd_sum"`
    WTDCount        int    `json:"wtd_count"`
    WTDSum          int    `json:"wtd_sum"`
}

注意:所有JSON标签必须使用英文双引号,否则json.Unmarshal会完全忽略标签规则。

二、修复CSV解析问题

核心问题是CSV中ItemRatings字段包含逗号和未正确转义的双引号,导致CSV reader错误拆分字段。以下是具体解决步骤:

1. 规范原始CSV格式

生成CSV时,必须将ItemRatings列用双引号包裹,且字段内的双引号按CSV规则转义为""(同时JSON内部的双引号保持\"格式)。修正后的CSV示例:

Date,RestaurantId,ItemRatings
2023-10-08,232,"[{""item_id"":8215117,""item_name"":""6"" pizza"",""current_day_count"":0,""current_day_sum"":0,""mtd_count"":1,""mtd_sum"":5,""wtd_count"":0,""wtd_sum"":0},{""item_id"":8215132,""item_name"":""The Great White"",""current_day_count"":0,""current_day_sum"":0,""mtd_count"":1,""mtd_sum"":5,""wtd_count"":0,""wtd_sum"":0}]"

解释:

  • 整个ItemRatings字段用双引号括起,避免内部逗号被当成CSV分隔符
  • CSV内的双引号转义为"",解析后再还原为JSON需要的"

2. 优化Go解析代码

调整CSV reader配置,同时处理JSON转义与聚合逻辑:

package main

import (
    "encoding/csv"
    "encoding/json"
    "fmt"
    "os"
    "strings"
)

type ItemRatings struct {
    RestaurantId int       `json:"restaurant_id"`
    Date         string    `json:"date"`
    ItemData     []ItemData `json:"item_data"`
}

type ItemData struct {
    ItemID          int    `json:"item_id"`
    ItemName        string `json:"item_name"`
    CurrentDayCount int    `json:"current_day_count"`
    CurrentDaySum   int    `json:"current_day_sum"`
    MTDCount        int    `json:"mtd_count"`
    MTDSum          int    `json:"mtd_sum"`
    WTDCount        int    `json:"wtd_count"`
    WTDSum          int    `json:"wtd_sum"`
}

func main() {
    file, err := os.Open("data.csv")
    if err != nil {
        panic(err)
    }
    defer file.Close()

    reader := csv.NewReader(file)
    reader.LazyQuotes = true        // 兼容字段内的未严格转义引号
    reader.FieldsPerRecord = 3      // 强制每行3个字段,防止JSON内逗号拆分字段
    reader.Comma = ','              // 明确分隔符(默认即为逗号,可省略)

    // 跳过表头行
    if _, err := reader.Read(); err != nil {
        panic(err)
    }

    // 按RestaurantId聚合的存储map
    restaurantAgg := make(map[int]*ItemRatings)

    for {
        record, err := reader.Read()
        if err != nil {
            break // 读取到文件结束时退出循环
        }

        // 解析RestaurantId
        restaurantId := 0
        fmt.Sscanf(record[1], "%d", &restaurantId)

        // 处理CSV转义:把""替换回",得到合法JSON字符串
        jsonStr := strings.ReplaceAll(record[2], `""`, `"`)

        // 解析ItemData数组
        var itemData []ItemData
        if err := json.Unmarshal([]byte(jsonStr), &itemData); err != nil {
            fmt.Printf("解析JSON失败: %v\n", err)
            continue
        }

        // 聚合逻辑:同一RestaurantId追加数据,否则新建条目
        if agg, ok := restaurantAgg[restaurantId]; ok {
            agg.ItemData = append(agg.ItemData, itemData...)
        } else {
            restaurantAgg[restaurantId] = &ItemRatings{
                RestaurantId: restaurantId,
                Date:         record[0],
                ItemData:     itemData,
            }
        }
    }

    // 输出聚合结果
    for id, data := range restaurantAgg {
        fmt.Printf("餐厅ID: %d\n", id)
        fmt.Printf("聚合数据: %+v\n\n", data)
    }
}

关键处理点:

  • reader.FieldsPerRecord = 3:强制固定字段数,避免JSON内的逗号误拆字段
  • strings.ReplaceAll(record[2], "", "):还原CSV转义的双引号为JSON格式
  • 用map[int]*ItemRatings实现按RestaurantId自动聚合,合并同一餐厅的所有ItemData

三、可选:替代CSV格式优化

如果无法修改原始CSV格式,可改用**制表符分隔(TSV)**替代CSV,因为制表符在业务数据中出现概率极低,彻底避免逗号和双引号的冲突:

Date	RestaurantId	ItemRatings
2023-10-08	232	[{"item_id":8215117,"item_name":"6\" pizza","current_day_count":0,"current_day_sum":0,"mtd_count":1,"mtd_sum":5,"wtd_count":0,"wtd_sum":0},{"item_id":8215132,"item_name":"The Great White","current_day_count":0,"current_day_sum":0,"mtd_count":1,"mtd_sum":5,"wtd_count":0,"wtd_sum":0}]

此时只需修改Go代码中CSV reader的分隔符:

reader.Comma = '\t'

无需处理双引号转义,解析逻辑更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 02:35:11