CSV是一种古老的数据传输格式,它的全称是Comma-Separated Values(逗号分隔值)。出生在那个标准缺失的蛮荒年代,CSV的标准一直(到2005年)是NULL——世间存在着N种CSV格式,它们自成体系,相互不兼容。比如我们从名字可以认为CSV至少是一种使用逗号分隔的格式,但是实际上,有的CSV格式却是使用分号(;)去做分隔。假如,不存在一种标准,那么这东西最终会因为碎片化而发展缓慢,甚至没落。本文讨论的CSV格式是基于2005年发布的RFC4180规范。我想,在这个规范发布之后,大家应该会更加自觉的遵从这套规范去开发——虽然这套标准依旧存在着一些致命的缺陷。(转载请指明出于breaksoftware的csdn博客)

我们可以从IETF上获得包含了CSV格式定义的文档。当然,如果你觉得看英文文档麻烦,你可以直接看我的下文。

  1. 在不包含换行符(CRLF即 \r\n)的单条信息时,数据要保持在一行,并且使用\r\n结束。
    aaa,bbb,ccc,dddCRLF   合法

    aaa,b                            内容中无换行符,而单条信息被换行,不合法
    bb.ccc,dddCRLF

  2. 最后一条信息可以没有换行符(当然有换行符也是合法的)
    aaa,bbb,ccc,dddCRLF
    eee,fff,ggg,hhh           合法

    aaa,bbb,ccc,dddCRLF
    eee,fff,ggg,hhhCRLF     合法

  3. 第一条信息可能是一个头信息。这个头信息和之后信息格式是相同的,并且和之后的信息有相同的模块数(上例中,aaa和bbb和ccc和ddd各被视为一个模块)。(个人认为这是RFC设计这个CSV格式的一个缺陷,因为这个规则将无法让我们从规则的角度去确认第一条信息到底是头信息还是普通信息。当然RFC这么设计肯定有它的原因。)
    index,character          合法,从字面意思上我们可以认为这个是头,当然我们也可以认为它不是头
    1,aCRLF
    2,bCRLF

    indexCRLF                 非法,模块数不统一
    1,aCRLF

  4. 每条信息都要使用半角逗号(,)分隔出若干模块。每条信息的模块数要相等。每条信息的最后一个模块之后不可以使用半角逗号。空格符被视为一个模块的内容而不可被忽略。(这条规则包含的信息量相对较多)
    aaa,bbbCRLF                合法
    ccc,ddd,CRLF                非法,一条信息的最后一个模块不可以使用半角逗号
    eee;ffffCRLF                   非法,要使用半角逗号分隔,而不是分号
    ggg,       h h h  CRLF     合法,注意hhh模块的若干个空格,它属于模块内容而不可以被忽略
    iii,jjj,kkkkCRLF               非法,模块数和上面不统一
  5. 每个模块首尾可以使用双引号扩住(当然也可以不使用)。如果不使用双引号扩住的模块,模块中不可以出现双引号。(言外之意:如果模块中出现双引号,则这个模块要用双引号将首尾扩住)
    “aaa”,bbbCRLF             合法
    a"aa,bbbCRLF              不合法,因为a"aa中包含了双引号,而这个模块没有被双引号扩住
  6. 如果模块中包含双引号、半角逗号或换行符,则模块首尾要用双引号扩住。
    "a\r\na"a,bbbCRLF       合法,第一个模块包含了换行符,要用双引号包含
    "a,aa",bbbCRLF            合法
  7. 当双引号出现在模块中,要将模块的首尾用双引号扩住,并且将模块中的一个双引号变成一对双引号。
    “a""aa”,bbbCRLF          合法,原始数据为a"aa,bbb

有了以上规则,我们可以编写出相应的提取算法。以下是我在工作中编写的一套从CSV文件中提取信息的核心代码

BOOL CCSV2Json::Parse()
{BOOL bSuc = FALSE;do {if ( INVALID_HANDLE_VALUE == m_hFile ) {break;}OVERLAPPED ov;memset(&ov, 0, sizeof(OVERLAPPED));BYTE lpBuffer[BUFFERSIZE] = {0};DWORD dwHaveRead = 0;std::string strSingle;BOOL bFirstDoubleQuotes = FALSE;    // 第一个字符是否为"BOOL bBeforeIsDoubleQuotes = FALSE; BOOL bBeforeIsX0D = FALSE;ListString Liststr;BOOL bPairDoubleQuotes = FALSE;while ( ReadFile(m_hFile, lpBuffer, sizeof(lpBuffer), &dwHaveRead, &ov ) ) {ov.Offset += dwHaveRead;for ( DWORD dwIndex = 0; dwIndex < dwHaveRead; dwIndex++ ) {BYTE& by = *(lpBuffer + dwIndex);if ( bFirstDoubleQuotes ) {// 有前置"if ( IsDoubleQuotes(by) ) {bBeforeIsX0D = FALSE;if ( bBeforeIsDoubleQuotes ) {strSingle.append(1, (char)(by));bBeforeIsDoubleQuotes = FALSE;}else {bBeforeIsDoubleQuotes = TRUE;}}else {if ( bBeforeIsDoubleQuotes ) {bFirstDoubleQuotes = FALSE;}bBeforeIsDoubleQuotes = FALSE;if ( IsCRLF( by ) ){if ( bFirstDoubleQuotes ) {strSingle.append(1, (char)(by));}else if (FALSE == bBeforeIsX0D) {Liststr.push_back(strSingle);m_Listliststr.push_back(Liststr);Liststr.clear();strSingle.clear();bFirstDoubleQuotes = FALSE;}bBeforeIsX0D = IsX0D(by);}else if ( IsSep(by) ) {bBeforeIsX0D = FALSE;if ( bFirstDoubleQuotes ) {strSingle.append(1, (char)(by));}else {bBeforeIsX0D = FALSE;Liststr.push_back(strSingle);strSingle.clear();}}else {bBeforeIsX0D = FALSE;strSingle.append(1, (char)(by));}}}else{// 如果无前置"if ( IsDoubleQuotes(by) ) {bBeforeIsX0D = FALSE;if ( strSingle.empty() ) {// 空串,第一个是"bFirstDoubleQuotes = TRUE;bBeforeIsDoubleQuotes = FALSE;}else {strSingle.append(1,(char)(by));continue;}}else {bBeforeIsDoubleQuotes = FALSE;if ( IsCRLF( by ) ){if (FALSE == bBeforeIsX0D) {Liststr.push_back(strSingle);m_Listliststr.push_back(Liststr);Liststr.clear();strSingle.clear();bFirstDoubleQuotes = FALSE;bBeforeIsDoubleQuotes = FALSE;}else {// 连续\r\n不考虑设置为新的行}bBeforeIsX0D = IsX0D(by);}else if ( IsSep(by) ) {bBeforeIsX0D = FALSE;Liststr.push_back(strSingle);strSingle.clear();}else {bBeforeIsX0D = FALSE;strSingle.append(1, (char)(by));}}}}memset(lpBuffer, 0, sizeof(lpBuffer));     }if ( false == strSingle.empty() ) {
//             while ( IsCRLF(strSingle.at(strSingle.length() - 1) ) && strSingle.length() > 0) {
//                 strSingle = strSingle.substr(0, strSingle.length() - 1 );
//             }Liststr.push_back(strSingle);m_Listliststr.push_back(Liststr);Liststr.clear();strSingle.clear();}bSuc = TRUE;} while (0);if ( NULL != m_hFile ) {CloseHandle(m_hFile);m_hFile = NULL;}return bSuc;
}

这段代码将CSV文件提取出来一个std::list<std::list<std::string>>结构。如上面名字所示,我这个功能是要将CSV文件转换为json格式,相应的我也编写了从json格式转换为CSV格式文件的代码。 这些代码都在工程中。

一种准标准CSV格式的介绍和分析以及解析算法相关推荐

  1. 前端json格式的介绍,转换以及解析

    近几日碰到json的问题比较多,我这里做一个总结,比较浅显简单,希望能对那些前端小白有所帮助,能对json有一个认识,并且能简单的处理json格式的内容. 例如最近碰到一个项目,项目需求如下: 用户选 ...

  2. python存储数据的操作(csv格式文件,Excel表格文件)!!!

    python存储数据 存储数据的方式 两种存储数据方式的区别 csv格式文件 Excel格式文件 csv文件的写入 csv文件的读取 Excel基本概念 Excel文件的写入 Excel文件的读取 存 ...

  3. ML之FE:基于FE特征工程对RentListingInquries数据集进行预处理并导出为三种格式文件(csv格式/txt格式/libsvm稀疏txt格式)

    ML之FE:基于FE特征工程对RentListingInquries数据集进行预处理并导出为三种格式文件(csv格式/txt格式/libsvm稀疏txt格式) 目录 输出结果 设计思路 核心代码 输出 ...

  4. csv文件导入后台乱码_用Excel打开CSV格式文件乱码,三种方法可以处理好!

    日常办公中,我们使用办公软件办公是比较平凡的,现在的办公软件也有好几种(微软的office.金山的WPS等).而且小编觉得在所有的办公软件中是微软的office是比较有名的.这款软件不仅功能齐全,还可 ...

  5. csv加header python_用python处理csv格式文件

    用python处理csv格式文件 在各种平台上获取数据时,我们常常获得的是csv格式的文件.csv格式是一种逗号分隔值的文件格式,它并不是非常reader-friendly.所幸,python标准库中 ...

  6. csv和excel php 解析_php读取csv文件(excel可另存为csv格式文件)

    csv文件简介 看到这个题目大家一定莫名其妙,这个csv文件和office有啥关系.呵呵,细心地朋友在用excel的时候会发现,excel可以另存为csv格式.我之前也对这个东西没什么了解,只是知道e ...

  7. Gox语言自动转换Excel文件为CSV格式-GX35.2

    本文继续介绍Gox语言中如何利用内置的github.com/360EntSecGroup-Skylar/excelize包来实现Excel文件的操作,例子中演示的是如何将Excel文件自动转换为CSV ...

  8. java 导出csv 格式,java导出csv格式文件的方法

    这篇文章主要为大家详细介绍了java导出csv格式文件的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 导出csv格式文件的本质是导出以逗号为分隔的文本数据 imp ...

  9. CSV格式数据如何导入MySQL?

    经常有客户咨询如何将CSV文件导入到MySQL数据库中,特写此文介绍一种方便.快捷的方法. 我们要使用的辅助工具是著名的MySQL管理软件:Navicat for MySQL 1)我准备了一个字符编码 ...

最新文章

  1. c语言指针编程易错点,C语言中指针的一些易错点!
  2. csdn上传资源提示“该资源已存在,请重新上传”
  3. Missing key(s) in state_dict
  4. MQTT客户端工具MQTTfx
  5. 关于js 中call()和 apply()方法的解释
  6. js javaScript array 取指定元素索引、判断是否相同、重复、过滤数据
  7. sql 显示百分比_轻松搞定数据分析之SQL——简单查询
  8. ios 图片逆时针旋转_iphone-IOS 竖直拍照被旋转,image-orientation 让图片自动旋转
  9. Verilog HDL中阻塞语句和非阻塞语句的区别
  10. 从zabbix的数据库获取数据
  11. 基于bootstrap table配置的二次封装
  12. 运营人员消消气,这个工具让数据分析轻松驾驭
  13. 割点(tarjan算法)
  14. LCD屏幕调试 ~ 字模提取工具和图片转码工具
  15. android截图保存在哪,电脑f12截屏一般保存在什么位置 | 手游网游页游攻略大全...
  16. 【JAVA】Java学习方法
  17. 安卓开发无线连接设备进行调试(adb)
  18. linux ntp时间同步失败,SUSE linux ntp时间不同步问题
  19. Linux 开发学习
  20. 我的电脑,虽然你很慢,但是我很爱你啊!

热门文章

  1. PCL调错:(3)error C2589“(“:“::“右边的非法标记
  2. 洛谷P2397 yyy loves Maths VI (mode) 摩尔投票
  3. Udacity机器人软件工程师课程笔记(二十七) - 卷积神经网络(CNN)
  4. PBR游戏3D模型合集包 PBR Game 3D-Models Bundle February 2022
  5. 从头开始学习Unity着色器
  6. Pliops XDP(Extreme Data Processor)数据库存储设计的新型加速硬件
  7. 搜索:深搜/广搜 获取岛屿数量
  8. Python - 在CentOS7.5系统中安装Python3
  9. ReentrantLock+线程池+同步+线程锁
  10. Android支付接入(五):机锋网