CSV 格式说明和应用
问题
我们常常将多个字符串item使用逗号拼接成一个字符串,用来表示数组,使用时再用逗号切割成为数组。比如安卓机型列表:
ALN-AL10,ALN-AL10,BRA-AL00,ALN-AL00/ALN-AL80
直到有一天,苹果设备也要用到这个机型列表,而它的每个机型都带着逗号,那我们使用逗号切割就得到了错误的数据。
iPhone15: iPhone15,4
iPhone15Plus: iPhone15,5
iPhone15Pro: iPhone16,1
iPhone15Pro_Max: iPhone16,2
为了解决这个问题,首先想到了换一个分隔符,比如 |
,再比如用一些不可见字符 : 0x01。
但我们不能保证这些字符串 item 一定不包含这些特殊字符,也许还有更好的方法。
既然是逗号分隔,首先想到的就是 CSV格式,毕竟 CSV 的全称就是Comma-Separated Values逗号分隔值。它是如何解决这个问题的?
CSV格式
CSV 的RFC说明文档:https://datatracker.ietf.org/doc/html/rfc4180
- 基本字段
- 包含逗号的字段,则使用双引号括起来;
- 包含双引号的字段,则在双引号前面必须加上另一个双引号进行转义。;
- 包含换行符的字段,则使用双引号括起来;
- 包含特殊字符的组合的字段,也是使用双引号括起来;
姓名,年龄,城市,备注
张三,30,北京,无备注
李四,25,上海,"喜欢, 打篮球"
王五,28,"广州, 广东",""
"李, 六",35,"""特别"" 市","这是一段
跨行的备注"
"陈, 七","40","深圳",
"包含""双引号""和,逗号"
使用 csv 的工具包是可以非常方便的处理这种数据。类似的后台表格导出 csv 文件也应当使用该csv工具包。
example:
Go 语言可以使用 https://pkg.go.dev/encoding/csv
func main() {
in := `姓名,年龄,城市,备注
张三,30,北京,无备注
李四,25,上海,"喜欢, 打篮球"
王五,28,"广州, 广东",""
"李, 六",35,"""特别"" 市","这是一段
跨行的备注"
"陈, 七","40","深圳","包含""双引号""和,逗号"
`
r := csv.NewReader(strings.NewReader(in))
for {
record, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
fmt.Println(record)
}
}
输出:
[姓名 年龄 城市 备注]
[张三 30 北京 无备注]
[李四 25 上海 喜欢, 打篮球]
[王五 28 广州, 广东 ]
[李, 六 35 "特别" 市 这是一段
跨行的备注]
[陈, 七 40 深圳 包含"双引号"和,逗号]
package utils
import (
`bytes`
`encoding/csv`
`strings`
)
// SliceToCsvString 将字符串切片转换为CSV字符串
func SliceToCsvString(slice []string) (string, error) {
var buf bytes.Buffer
writer := csv.NewWriter(&buf)
// 写入单行数据
err := writer.Write(slice)
if err != nil {
return "", err
}
// 确保所有数据都被写入
writer.Flush()
// 检查是否有任何错误
if err := writer.Error(); err != nil {
return "", err
}
return buf.String(), nil
}
// CsvStringToSlice 将CSV字符串转换为字符串切片
func CsvStringToSlice(csvString string) ([]string, error) {
reader := csv.NewReader(strings.NewReader(csvString))
reader.ReuseRecord = true
// 读取所有记录
records, err := reader.Read()
if err != nil {
return nil, err
}
return records, nil
}