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
相关产品推荐
相关产品推荐

