Excel 数据怎么给前端用?CSV 转 JSON 的类型丢失坑
上周帮一个同事联调,他拿着 Excel 导出的用户表做 Demo,导成 CSV 喂给前端组件。页面一刷新,他指着年龄排序说:「这排序有问题吧,100 排在 20 前面。」我让他 console.log 看一眼数据,age 字段全是字符串 "30"、"100"、"20"。按字符串比字典序,"100" 当然排在 "20" 前面。
这事不止他踩过。CSV 转成 JSON 看似只是换个壳,里面有两个坑能让你 debug 大半天,今天就把这两个讲透。
第一个坑:CSV 没有类型,数字会变成字符串
JSON 有类型,字符串、数字、布尔、数组、对象分得清清楚楚。CSV 没有。CSV 文件里存的就是字符,30 和 "30" 在底层是一回事,没人标记哪个是数字哪个是文本。所以一旦把 CSV 转 JSON,所有字段默认都变成字符串。
看这个 CSV:
name,age,active
Alice,30,true
Bob,25,false
转完你以为是这样的:
[
{ "name": "Alice", "age": 30, "active": true },
{ "name": "Bob", "age": 25, "active": false }
]
实际拿到的是:
[
{ "name": "Alice", "age": "30", "active": "true" },
{ "name": "Bob", "age": "25", "active": "false" }
]
注意 age 是字符串 "30",active 是字符串 "true",不是布尔。这俩到了前端,"30" + 5 给你拼成 "305",if (data.active) 不管值是 "true" 还是 "false",只要非空字符串就一律为真。
修复办法是在拿到 JSON 后,对已知字段手动转一次:
const users = raw.map(u => ({
...u,
age: Number(u.age),
active: u.active === 'true',
}))
不要指望转换工具替你猜类型。CSV 里 007(工号)和 7(年龄)长得一样,工具没法判断哪个该保留前导零、哪个该转数字。类型语义只有写代码的人知道,转换完手动处理这一步不能省。
第二个坑:字段里含逗号,一行被拆成好几列
CSV 用逗号分隔字段,那字段值本身带逗号怎么办?RFC 4180 给了规则:用双引号把整个值包起来。引号本身用两个连续双引号 "" 转义,注意不是反斜杠。
看这行:
1,张三,"北京,朝阳",30
"北京,朝阳" 这一段是一个字段,解析出来应该是字符串 北京,朝阳。如果你的解析器不认双引号包裹,简单按逗号切分,这一行就变成五个字段:
1 | 张三 | "北京 | 朝阳" | 30
表头只有四列,数据冒出五列,要么报错要么错位,整张表废了。
更隐蔽的是引号本身的转义。CSV 字段里要表示一个双引号字符,写法是 "",不是 \"。比如存一个备注 说了一句"你好",正确写法:
1,张三,"说了一句""你好""",30
解析出来第三个字段是 说了一句"你好"。这一点很多人下意识写成反斜杠转义,因为 JSON 和编程语言里都是反斜杠那一套,到了 CSV 这规则变了,得专门记一下。
还有一个容易漏的情况:字段里有换行符。RFC 4180 允许双引号包裹的字段跨行,值里可以包含 \n。简单按行切分再按逗号切分的实现会把一条记录拆成两条。靠谱的 CSV 解析器都得维护一个「是否在引号内」的状态机,遇到引号才切换。
分隔符的地区差异
逗号不是全世界唯一的分隔符。欧洲很多国家用逗号当小数点,3,14 就是 3.14,CSV 自然不能再用逗号当分隔符,普遍改用分号。所以从法国、德国系统导出的 CSV 经常长这样:
name;price;stock
Baguette;1,50;100
国内的坑主要是 Excel。你从 Excel 里复制一块数据,粘贴到文本编辑器里,经常发现分隔符是 Tab,不是逗号。直接粘到只认逗号的工具里,整张表挤在一列,所有字段首尾相连。
处理办法是转换时按数据来源选分隔符:标准 CSV 用逗号,欧洲来源数据看分号,Excel 复制来的用 Tab。如果不确定,肉眼扫一下原文,看哪种符号出现得规律。
实操
手动写 CSV 解析器没必要,标准库和在线工具都帮你处理好了引号转义和分隔符问题。需要快速核对转换结果时,可以丢进 UPTools CSV/JSON 互转工具 里:支持逗号、分号、Tab 三种分隔符,第一行自动当表头,转完有表格预览能直接看到字段对位有没有错。处理过程全在浏览器本地,数据不出机器。
至于类型那一步,工具帮不上忙,转换完在代码里自己 Number() 一下。
三句话总结
CSV 无类型,转 JSON 后数字和布尔都变字符串,已知的数值字段要手动 Number() 或比较字符串修复。字段含逗号或引号要按 RFC 4180 用双引号包裹,引号本身用两个连续双引号转义,不是反斜杠。分隔符按数据来源定,欧洲常见分号、Excel 复制常见 Tab,解析前先看一眼原文。
相关文章