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

  1. 基本字段
  2. 包含逗号的字段,则使用双引号括起来;
  3. 包含双引号的字段,则在双引号前面必须加上另一个双引号进行转义。;
  4. 包含换行符的字段,则使用双引号括起来;
  5. 包含特殊字符的组合的字段,也是使用双引号括起来;
姓名,年龄,城市,备注
张三,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
}

Read more

代码 Refactoring

重构不必谈之色变。 它也不是洪水猛兽,而是开发过程中持续进行的优化过程。让我们开始学习这个主题,重新认识它的价值。 🌟整洁代码 重构的主要目的是消除技术债务。它将混乱变成整洁的代码和简单的设计。 * 对于其他程序员来说,整洁的代码是显而易见的。 我并不是在谈论超级复杂的算法。糟糕的变量命名、臃肿的类和方法、魔法数字 - 等等,所有这些都会让代码变得混乱和难以理解。 * 整洁的代码不包含重复。 每次你需要对重复的代码进行更改时,你都必须记住对每个实例进行相同的更改。这会增加认知负担并减慢进度。 * 整洁的代码包含最少数量的类和其他活动部件。 代码越少,脑子里需要记住的东西就越少。代码越少,维护工作就越少。代码越少,错误就越少。代码就是责任,保持代码简短。 * 整洁的代码通过所有测试。 如果只有 95% 的测试通过,你就知道代码不整洁。如果测试覆盖率为 0%,你就知道你完蛋了。 * 整洁的代码维护成本低! 🗑️技术债(What) 每个人都尽最大努力从头开始编写出色的代码。可能没有程序员会故意编写不干净的代码,从而损害项目。但是干净的代码在什么时

By brian
开启了http2,但是http2_max_field_size 还在用默认值吗?

开启了http2,但是http2_max_field_size 还在用默认值吗?

排查1个异常接口,学到一个降本和接口提速的新思路。另外找到1个charles的"bug" 现象 测试同学反馈在iOS13设备上请求接口报错,将请求复制为 curl 命令。分别导入 apifox 和 在终端执行: * 在 apifox 请求正常 ✅ * 在终端请求失败 ❌ curl: (56) Failure when receiving data from the peer 测试同学又反馈另一个手机支持请求接口返回正常。 定位 有了正常和错误的请求curl,那直接对比二者差异就很简单了。对比发现,在终端执行失败的请求中多了一个较大的Cookie: app_token。按历史经验基本能确定是因为 Cookie 这个 header 条目太大,超过服务器的限制。 找云平台确定相关配置: ELB http1: header头限制 128KB,body 限制一个10G http2:

By brian

Minikube 操作开启 ipvs

1. 编辑 kube-proxy 配置 编辑 kube-proxy 配置以启用 ipvs 模式。您可以使用以下命令编辑配置: kubectl edit configmap kube-proxy -n kube-system 在配置中,找到 mode 字段并将其设置为 ipvs。例如: apiVersion: v1 kind: ConfigMap metadata: name: kube-proxy namespace: kube-system data: mode: "ipvs" 保存并关闭配置。 2. 重新启动 kube-proxy 重新启动 kube-proxy 以应用新配置: kubectl rollout restart daemonset kube-proxy -n kube-system

By brian

在 Minikube 中直接上手学习 K8S Service

K8S 为什么需要 Service? 1. Pod 的 IP 不是固定的; 2. 一组 Pod 实例之间有负载均衡的需求; 上机操作 以下使用 minikube 作实例: # 安装 brew install minikube # 启动 minikube start # 创建 ~/.kube/config 请注意先备份 minikube update-context # 进入宿主机 minikube ssh 集群启动后,创建 Deployment 和 Service apiVersion: v1 kind: Service metadata: namespace: default name: nginx-svc spec: type: NodePort selector:

By brian
沪ICP备2022013452号-1