一种准标准CSV格式的介绍和分析以及解析算法
CSV是一种古老的数据传输格式,它的全称是Comma-Separated Values(逗号分隔值)。出生在那个标准缺失的蛮荒年代,CSV的标准一直(到2005年)是NULL——世间存在着N种CSV格式,它们自成体系,相互不兼容。比如我们从名字可以认为CSV至少是一种使用逗号分隔的格式,但是实际上,有的CSV格式却是使用分号(;)去做分隔。假如,不存在一种标准,那么这东西最终会因为碎片化而发展缓慢,甚至没落。本文讨论的CSV格式是基于2005年发布的RFC4180规范。我想,在这个规范发布之后,大家应该会更加自觉的遵从这套规范去开发——虽然这套标准依旧存在着一些致命的缺陷。(转载请指明出于breaksoftware的csdn博客)
我们可以从IETF上获得包含了CSV格式定义的文档。当然,如果你觉得看英文文档麻烦,你可以直接看我的下文。
- 在不包含换行符(CRLF即 \r\n)的单条信息时,数据要保持在一行,并且使用\r\n结束。
aaa,bbb,ccc,dddCRLF 合法
aaa,b 内容中无换行符,而单条信息被换行,不合法
bb.ccc,dddCRLF - 最后一条信息可以没有换行符(当然有换行符也是合法的)
aaa,bbb,ccc,dddCRLF
eee,fff,ggg,hhh 合法
aaa,bbb,ccc,dddCRLF
eee,fff,ggg,hhhCRLF 合法 - 第一条信息可能是一个头信息。这个头信息和之后信息格式是相同的,并且和之后的信息有相同的模块数(上例中,aaa和bbb和ccc和ddd各被视为一个模块)。(个人认为这是RFC设计这个CSV格式的一个缺陷,因为这个规则将无法让我们从规则的角度去确认第一条信息到底是头信息还是普通信息。当然RFC这么设计肯定有它的原因。)
index,character 合法,从字面意思上我们可以认为这个是头,当然我们也可以认为它不是头
1,aCRLF
2,bCRLF
indexCRLF 非法,模块数不统一
1,aCRLF - 每条信息都要使用半角逗号(,)分隔出若干模块。每条信息的模块数要相等。每条信息的最后一个模块之后不可以使用半角逗号。空格符被视为一个模块的内容而不可被忽略。(这条规则包含的信息量相对较多)
aaa,bbbCRLF 合法
ccc,ddd,CRLF 非法,一条信息的最后一个模块不可以使用半角逗号
eee;ffffCRLF 非法,要使用半角逗号分隔,而不是分号
ggg, h h h CRLF 合法,注意hhh模块的若干个空格,它属于模块内容而不可以被忽略
iii,jjj,kkkkCRLF 非法,模块数和上面不统一 - 每个模块首尾可以使用双引号扩住(当然也可以不使用)。如果不使用双引号扩住的模块,模块中不可以出现双引号。(言外之意:如果模块中出现双引号,则这个模块要用双引号将首尾扩住)
“aaa”,bbbCRLF 合法
a"aa,bbbCRLF 不合法,因为a"aa中包含了双引号,而这个模块没有被双引号扩住 - 如果模块中包含双引号、半角逗号或换行符,则模块首尾要用双引号扩住。
"a\r\na"a,bbbCRLF 合法,第一个模块包含了换行符,要用双引号包含
"a,aa",bbbCRLF 合法 - 当双引号出现在模块中,要将模块的首尾用双引号扩住,并且将模块中的一个双引号变成一对双引号。
“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格式文件的代码。 这些代码都在工程中。 相关文章:
新战场路在何方——详解360金融数据中台之旅
作者 |360金融架构总监黄建庭出品 | AI科技大本营(ID:rgznai100)本文为CSDN即将推出的《新战场:决胜中台》专刊的第 4 篇文章。自阿里巴巴引入中台概念后,市场对中台的关注度持续“高烧”不退。作为企业的基础平台,数据…

oracle中的exists 和not exists 用法详解
有两个简单例子,以说明 “exists”和“in”的效率问题 1) select * from T1 where exists(select 1 from T2 where T1.aT2.a) ; T1数据量小而T2数据量非常大时,T1<<T2 时,1) 的查询效率高。 2) select * from T1 where T1.a in (select…

现代内存编号解读(转)
现代SDRAM、DDR SDRAM、DDR2 SDRAM三种主流内存颗粒的编号一、DDR SDRAM:HYNIX DDR SDRAM颗粒编号:HY XX X XX XX X X X X X X X — XX X1 2 3 4 5 6 7 8 9 10 11 12 — 13 14整个DDR SDRAM颗粒的编号,一共是由14…
被追捧为“圣杯”的深度强化学习已走进死胡同
作者 | 朱仲光编译 | 夕颜出品 | AI科技大本营(ID:rgznai1100)【导读】近年来,深度强化学习成为一个被业界和学术界追捧的热门技术,社区甚至将它视为金光闪闪的通向 AGI 的圣杯,大多数人都看好它未来发展的巨大潜力。但…
一种清除windows通知区域“僵尸”图标的方案——问题分析
通知区域名称有趣的历史 假如说到windows通知区域,可能很多人还是不清楚它是什么。如果改称Tray区域,可能有人就懂了。如果再白话点,叫它“托盘”或者“系统托盘”,可能会有更多的人猜到它是windows什么部位。现在我们揭开…

Apache2.4+Tomcat7集群搭建
一、安装jdk、Tomcat、Apache1.安装jdk1.7cd /home/java/software #把软件下载到/home/java/software目录下,将应用安装到/home/java目录下。 wget http://download.oracle.com/otn/java/jdk/7u80-b15/jdk-7u80-linux-x64.tar.gz tar -zxvf jdk-7u80-linux-x64.tar…
一种清除windows通知区域“僵尸”图标的方案——XP系统解决方案
XP下“僵尸”图标的解决方案 从《一种清除windows通知区域“僵尸”图标的方案——问题分析》(以后简称《问题分析》)一文中分析的通知区域结构可以看出,XP的通知区域结构是相对简单的。如果我们解决了XP下的问题,那么Win7上的问题…

《评人工智能如何走向新阶段》后记(再续12)
由AI科技大本营下载自视觉中国151. 新一代人工智能研究方向: (1)研究新一代人工智能基础理论(机理、模型和算法);(2)研发面向需求的共性技术(以神经网络和算法为核心、数据和硬件为基…

正则表达式测试工具 Regex Tester 的使用方法
2019独角兽企业重金招聘Python工程师标准>>> 正则表达式测试工具“RegexTester”,下载地址:http://www.oschina.net/p/regextester 一、关于本文 今天的工作中遇到了一些正则表达式,我需要检验它们是否正确,不过我对自…
一种清除windows通知区域“僵尸”图标的方案——Windows7系统解决方案
Windows7下“僵尸”图标的解决方案 从《一种清除windows通知区域“僵尸”图标的方案——问题分析》(以后简称《问题分析》)一文中分析的通知区域结构可以看出,Windows7的通知区域比XP通知区域多出了一个“临时”系统通知区域(转载…

《评人工智能如何走向新阶段》后记(再续13)
由AI科技大本营下载自视觉中国161. 引自美国科技媒体TNW记者对美欧企业主管与AI专家的访谈录摘要,谈到2020年AI的八大趋势: ①人工智能将使医疗保健更准确、成本更低; ②可解释性和信托及AI伦理将受到更多关注; ③在人工智能领…

在特定情况下的简单SSO实现方案
最近需要实现类似单点登录的功能。情况是这样的,最初在做网站A,做着做着,要做网站B了,要求与网站A完全分开作为两个应用,但用户数据要求与网站A保持一致,也要求用户在网站A登录后,转到网站B时不…

为创业者保驾护航 “无安全 不创业” 安全狗全国路演北京站
2019独角兽企业重金招聘Python工程师标准>>> 2015年上半年,网络安全问题毫无疑问已经成为了互联网行业关注的重点。在短短一年多的时间里,网络安全问题就从隐患转而呈现出爆发之势,即使是网易、支付宝、携程这样的互联网行业巨头也…
一种将快捷方式从开始菜单“常用应用”的中去除的方法
当我们安装一款软件的时候,这款软件的一些快捷方式可能被设置到开始菜单的“常用应用”区域。但是,如果是“卸载”快捷方式被“钉”到该区域,就会造成非常不好的体验。毕竟把“卸载”接口暴露得如此醒目,如同把该款软件的地狱大门…

ISA---不能访问网址或是多次刷新才能访问的解决方法一则
当你安装ISA2006在WINDOWS 2003 SERVER上,并打上SP2补订时。遇SNAT客户端不能访问WEB,但能PING通,能TELNET通,也能访问QQ或是MSN的问题时可以利用以下方法解决。同时,如果你遇到在此环境下,客户端访问外部网…

《评人工智能如何走向新阶段》后记(深谈人工智能发展前沿)
由AI科技大本营下载自视觉中国来自国内外的跟贴留言 深谈人工智能发展前沿 自从我们发表《评人工智能如何走向新阶段》一文以来,至今约5个月,引来了中外专家、草根们的大量跟贴留言(也有人转录他人的公开言论作为跟贴来发表的)。…

URAL 2027 URCAPL, Episode 1 (模拟)
题意:给你一个HxW的矩阵,每个点是一个指令,根据指令进行一系列操作。 题解:模拟 #include<cstdio> #include<algorithm> using namespace std;const int maxn 101; char G[maxn][maxn];int dx[] {-1,0,1, 0}; int d…

使用WinHttp接口实现HTTP协议Get、Post和文件上传功能
我实现了一个最新版本的接口,详见《实现HTTP协议Get、Post和文件上传功能——使用WinHttp接口实现》。还有基于libcurl实现的版本《实现HTTP协议Get、Post和文件上传功能——使用libcurl接口实现》。以下是原博文: 我们在做项目开发时,往往会…
收藏 | 一文带你总览知识蒸馏,详解经典论文
「免费学习 60 节公开课:投票页面,点击讲师头像」作者:凉爽的安迪来源 | 深度传送门(ID:deep_deliver)【导读】这是一篇关于【知识蒸馏】简述的文章,目的是想对自己对于知识蒸馏学习的内容和问题…

[工具推荐]用了TrueCrypt 再无难掩之隐
缘起:混在网络n多年了,手头总有些东西不想被别人看到的东西,由于小弟人品好,相貌佳,总有很多朋友喜欢用我的电脑玩啊玩啊……。 近日,冠希、柏芝等前辈以身示法,为我等上了很好一堂关于隐私保护…

利用phpmailer类邮件发送
<?phprequire("class.phpmailer.php"); //下载的文件必须放在该文件所在目录$mail new PHPMailer(); //建立邮件发送类$address "接收方邮箱"; //接收方地址$mail->IsSMTP(); //使用SMTP方式发送$…
据说这是大多数人【减肥】的真实写照
有句诗说得好 “冬天不减肥,夏天徒伤悲” 在这个人人储存脂肪的季节绝对是你甩掉脂肪的好时机(毕竟这是一个拼颜值的时代颜值是天生的,可是身材绝不能输)但是 据说大多数人的减肥经历其实是这样的减肥第一步管住嘴,迈开…
PE文件和COFF文件格式分析——导出表的应用——一种摘掉Inline钩子(Unhook)的方法
在日常应用中,某些程序往往会被第三方程序下钩子(hook)。如果被下钩子的进程是我们的进程,并且第三方钩子严重影响了我们的逻辑和流程,我们就需要把这些钩子摘掉(Unhook)。本件讲述一种在32位系统上,如何摘掉API钩子的思路和方法。…

设置列表字段为主键
转贴:Sample event handler to set a field as a pr imary key (enforce no duplicates) Got this as a request from a reader- how to prevent users from adding items with same titles as ones that already exist in the list. Codeusing System;using System.Collectio…

谁登录了你的linux
最近有一台数据库服务器自动重启。查了一下相关登录信息:查看linux下的用户登录日志,包括用户登录时所用的主机的ip:more /var/log/secure who /var/log/wtmp干了些什么? root账户下输入su - username 切换到username下输入 histo…
一种使用GDI+对图片尺寸和质量的压缩方法
今天同事向我询问图片压缩的算法,我想起大概两三年前做过的一个项目。其中包含了尺寸和质量两种压缩算法,并且支持JPEG、bmp、PNG等格式。今天把这段逻辑贴出来,供大家参考。(转载请指明来源于breaksoftware的CSDN博客)…

.NET企业级应用架构设计系列之应用服务器
本文属spanzhang(张友邦)原创,发布地址为:http://blog.csdn.net/spanzhang。转载或引用请注明原文之出处,谢谢! .NET企业级应用架构设计系列之开场白 .NET企业级应用架构设计系列之技术选型 这里要说到的…
编程语言发展70年,用50种不同语言输出「Hello World」
「免费学习 60 节公开课,投票页面,点击讲师头像」作者 | Sylvain Saurel译者 | 风车云马责编 | 屠敏【导读】历经 70 年,不断出现的编程语言为开发者解决了哪些难题?其存在又有怎样的特性?本文将以「Hello World」为例…

函数循环的理解
2019独角兽企业重金招聘Python工程师标准>>> var ulObjdocument.getElementById("box"); var lisObjulObj.getElementsTagname("li"); for(var i0;i<lisObj.length;i) { lisObj[i].οnclickfunction()//循环时对应节点绑定事件,事…
从LeNet到GoogLeNet:逐层详解,看卷积神经网络的进化
「免费学习 60 节公开课:投票页面,点击讲师头像」作者 | MrCharles来源 | CSDN原力计划获奖作品(*点击阅读原文,查看作者更多文章)前言深度学习的兴起使卷积神经网络在计算机视觉方面大放异彩,本文将按时间…