其实你不一定懂csv文件格式

最近业务中涉及到了csv文件的读写,本以为是非常简单的一件事情。结果却踩了几个坑。想象一下下面这段写csv文件的代码有什么问题?

$arr = [
    ["this is a string", "another string", "Hello\nWorld", "你好,世界"],
    [".....", ".....","xxx","111"]
];

$filepath = "/home/zhangsan/output.csv";
foreach ($arr as $key => $val) {
    file_put_contents($filepath, implode(",", $val) . "\n", FILE_APPEND);
} 

代码功能很简单,就是把一个字符串二维数组写入csv文件中存储。正常情况下还好,然后二维数组中如果有的字符串里面本来就有换行符或者逗号,瞬间懵逼。于是去认真调研了一把csv文件格式,分享给大家。

无论是平时办公还是网络传输,csv(Comma Separated Values)文件都是非常常用的文件格式。正如它英文直译过来的意思一样,逗号分隔符文件,每个文件类似于一个表格,换行意味着表格的一行结束,而英文逗号用于将每一行分隔为一个个的单元格。直观理解起来,你可能会觉得非常简单。不过在此之前,不妨先回答以下几个问题, 如果都能知道答案,那确实是已经非常熟悉这个文件格式了。

【1】 csv文件能否允许每一行的单元格数量不一样?

【2】 单元格之间用逗号分隔,那如果单元格内容里面本身就有个逗号怎么处理?

【3】 同理,换行用于开启一行新的数据,但是如果单元格内容里面本身就有换行符怎么处理?

【4】 csv文件是否应该有表头?即第一行应该是表头还是数据?

【5】 每行最后一个单元格的数据后面能否有逗号?

要找对于csv文件最权威的定义,就要先介绍一下RFC(Request For Comments)了。RFC可以认为是世界上最权威的互联网基本概念介绍大全,每个概念的介绍都有自己的一个文件编号。例如JSON格式的定义文件(RFC4627),HTTP2.0的定义文件(RFC7540),PNG图片格式定义文件(RFC2083)等等。在此不做过多介绍,想要了解RFC的由来可以参考维基百科,如果感兴趣想了解所有的RFC文件,可参考其官方网站

回到主题,对于csv文件格式,RFC也有其官方文档描述,即RFC4180。该文档其实是汇总了各家的csv文件实现方式,并且选取了最大众化的,被最多人所接受格式并计入此标准中。该文档其实已经可以回答我们上方的几个问题。

【1】 csv文件能否允许每一行的单元格数量不一样?

不允许,每一行(包括表头行)均拥有相同数量的单元格

【2】 单元格之间用逗号分隔,如果单元格内本身有逗号怎么处理?

整个单元格可以用双引号包含起来。也就是说如果单元格内容没有逗号,那么你可以任何选择是否要用双引号把单元格包含起来。这就带来另一个问题,如果单元格内容本身有双引号呢?你必须使用双引号包含整个单元格,并且内容中的双引号前面要多加一个双引号做转义。例如:

// 正确,hello与world之间有逗号所以必须用引号包含起来,其他单元格随意
nihao,qcloud,qq,"weixin" 
hi, taobao,"hello, world", tmall 


// 正确,注意第二行第三个单元格内容本来是she said "yes"
// 但是由于内容本身有双引号,所以单元格用双引号包含,且内容中的双引号多写一个做转义
nihao,qcloud,qq,"weixin" 
hi, taobao,"she said ""yes""", tmall 


// 错误,没有用双引号包含的单元格不准出现双引号
nihao,qcloud,qq,"weixin"
hi,taobao,1'10" so fast,tmall

【3】 单元格内容本身有换行符怎么处理?

同上,单元格用引号括起来。举例

// 正确,下面内容虽然占三行,但是只认为有两行csv数据,"weixin \n a life style"算一个单元格
nihao,qcloud,qq,"weixin
a life style"
hi,taobao,1'10" so fast,tmall

【4】 csv文件是否应该有表头?

随意,可以有也可以没有。只不过表头行的单元格数量要保持和数据一致

【5】 每行的最后一个单元格后面能否有逗号?

不可以,以逗号结尾的行被认为最后有个空的单元格。

另外需要注意的是,csv和http协议一样,换行符是“\r\n”(即CRLF),只不过大部分csv相关的库做了兼容,可以兼容以"\r"或者"\n"结尾的情况。当你自己要用程序写入内容到csv文件,或者要写一个读取csv文件的程序时,这些规则就显得尤为重要了。各个开发语言也都针对csv文件的写入和读取有专门的开源库。切不可在小问题上栽了大坑。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏ytkah

整理的dedecms标签大全,方便查找

  平时用dedecms开发经常会用到一些标签,特别是首页、栏目页、内容页,这些页面都会用到标签的调用,比如title、keywords、description...

2765
来自专栏知道一点点

angularjs中常用的ng指令介绍【转载】

原文:http://www.cnblogs.com/lvdabao/p/3379659.html

1113
来自专栏Spring相关

前端的CRUD增删改查的小例子

1083
来自专栏Java帮帮-微信公众号-技术文章全总结

深入浅出爬虫之道: Python、Golang与GraphQuery的对比

本文将分别使用 Python ,Golang 以及 GraphQuery 来解析某网站的 素材详情页面 ,这个页面的特色是具有清晰的数据结构,但是DOM结构不够...

941
来自专栏Alan's Lab

如何编写一个 jQuery 插件

https://github.com/zcfan/sket... 重写了本文的初步功能实现,支持一个页面多个画图板。但为简单起见,本文保持不变。

1244
来自专栏DeveWork

WordPress 中部署真正的懒加载(Lazy Load)

不少WordPress 主题(包括DeveWork.com目前的主题)都有部署jquery 插件“懒加载”(Lazy Load),但其实很多都不能产生真正的懒加...

2137
来自专栏逸鹏说道

Jupyter-Notebook版的博客园美化

文章汇总:https://www.cnblogs.com/dotnetcrazy/p/9160514.html

1402
来自专栏IT开发技术与工作效率

VBA常用程序——每个表都应该有

1463
来自专栏更流畅、简洁的软件开发方式

见到了“公司”定义一个Company类,那么见到了“字段”是不是也可定义一个Column类?

  既然见到了公司,我们可以定义一个Class Company ,那么我们见到了字段,是不是也可以定义一个Class ColumnInfo呢? 公司的描述信息类...

2479
来自专栏林德熙的博客

win10 uwp ContentDialog 点确定不关闭

微软的ContentDialog不是一直有,而是UWP新的,可以使用Content放用户控件,使用很好,但是一点不好的是,默认的一点击下面按钮就会退出。

1152

扫码关注云+社区