简单的csv文件解析

csv文件的结构很简单,最基本的规则,就是用逗号分隔每一个单元格,用换行( 或者 )分隔每一列。其中需要注意的就是双引号为特殊的转义字符。详细的csv文件格式定义,在rfc4180中,主要的定义为:

file = [header CRLF] record *(CRLF record) [CRLF]

header = name *(COMMA name)

record = field *(COMMA field)

name = field

field = (escaped / non-escaped)

escaped = DQUOTE *(TEXTDATA / COMMA / CR / LF / 2DQUOTE) DQUOTE

non-escaped = *TEXTDATA

COMMA = %x2C

CR = %x0D

DQUOTE = %x22

LF = %x0A

CRLF = CR LF

TEXTDATA = %x20-21 / %x23-2B / %x2D-7E

根据这个定义,用状态机的方法,定义状态的枚举:

enum CSV_STATE

{

CELL_BEGIN,//单元格开始

CELL,//单元格

CELL_END,//单元格结束

QUOTATION_1,//第一个引号

QUOTATION_2,//第二个引号

QUOTATION_3,//第三个引号

ESCAPED_CELL, //转义的单元格

};

之前画的状态迁移图没有保存,直接上代码:

case CELL_BEGIN:

if (*iter == ‘\”‘) //第一个引号开始

{

_state = QUOTATION_1;

}

else if(*iter == ‘,’)//逗号,一个空的单元格

{

row._rowData.push_back(“”);

_cell.clear();

}

else//有中文,其他字符都保存

{

_cell.push_back(*iter);

_state = CELL;

}

break;

case CELL:

if(*iter == ‘\”‘)//rfc4180 未转义的单元格内不能出现引号

{

//简单处理,直接抛出异常

throw std::runtime_error(“error parse csv format arround: ” + line);

}

else if(*iter == ‘,’) //逗号,改单元格结束

{

row._rowData.push_back(_cell); //rfc4180规定单元格能够有空格,后面的空格暂时不管

_cell.clear();

_state = CELL_BEGIN;

}

else//因为有中文,不过滤rfc4180中排除的其他字符

{

_cell.push_back(*iter);

}

break;

case QUOTATION_1:

if(*iter == ‘\”‘)//第二个引号

{

_state = QUOTATION_2;

}

else

{

_cell.push_back(*iter);

_state = ESCAPED_CELL;

}

break;

case QUOTATION_2:

if(*iter == ‘\”‘)//第三个引号,为引号的转义

{

_cell.push_back(*iter);

_state = ESCAPED_CELL;

}

else if(*iter == ‘,’)//没有第三个引号,单元格结束

{

row._rowData.push_back(_cell);

_cell.clear();

_state = CELL_BEGIN;

}

else//其他字符,全部忽略

{

row._rowData.push_back(_cell);

_cell.clear();

_state = CELL_END;

continue;

}

break;

case CELL_END:

if(*iter == ‘,’)//忽略其他字符,遇到逗号,表示新的单元格开始了

{

_state = CELL_BEGIN;

}

break;

case ESCAPED_CELL:

if(*iter == ‘\”‘) //第二个引号

{

_state = QUOTATION_2;

}

else

{

_cell.push_back(*iter);

}

break;

每次读取一行进行解析,开始解析前,初始状态是CELL_BEGIN,解析完成后,有两种可能的状态:

1、处于CELL或者QUOTATION_2状态,因为最后一个单元格是没有逗号的,解析完成后,将最后一个单元格的数据push_back进去

2、处于ESCAPED_CELL状态,因为转义的单元格中间是可以包含换行的,所以需要返回false,继续下一行的读取

3、处于其他状态,应该是不可能的,

if(_state == ESCAPED_CELL) //转义单元格可以包含换行,还在这个单元格,需要继续解析下一行

{

_cell.push_back(‘\n’);//getline把本来应该存在的换行吃了,补回去

return false;

}

else if (_state == CELL || _state == QUOTATION_2) //最后一个单元格,保存下

{

row._rowData.push_back(_cell);

_cell.clear();

_state = CELL_BEGIN;

}

这里做的和rfc文档不同的是,rfc定义的文本字符,是 %x20-21 / %x23-2B / %x2D-7E,但因为csv中可能包含中文,所以除了特殊字符(逗号和双引号)之外,没有再判断字符的有效性。

转载自:https://coolex.info/blog/171.html

时间: 2024-09-16 01:29:14

简单的csv文件解析的相关文章

CSV 文件解析

介绍     在很多时候,数据是以CSV文件格式存放的.在提取CSV数据时,我们借助javacsv这个开源工具来处理,还是比较方便. javacsv in pom.xml of Maven <dependency> <groupId>net.sourceforge.javacsv</groupId> <artifactId>javacsv</artifactId> <version>2.0</version> </d

使用boost::spirit实现的CSV文件解析类

boost::spirit真是不错的说.... #include <iostream>#include <iterator>#include <vector>#include <string>#include <boost/spirit/core.hpp>#include <boost/spirit/iterator/file_iterator.hpp>using namespace std;using namespace boost

java数组-解析csv文件为数组怎么做?

问题描述 解析csv文件为数组怎么做? 小弟,新人,第一次问问题,大神们,帮我看看怎么弄-有一个csv文件的数据文件(里面大概存了200条的数据)怎样把它处理一下,写入到数据库中呢?要求3分钟内实现,插入完成! PS--要用批处理吗? 解决方案 http://lqcjdx.blog.163.com/blog/static/207489241201356111749932/ 解决方案二: CSV 文件解析解析CSV文件csv文件格式化数组 解决方案三: 建一个跟csv列对应的表,在plsql里,s

《精通自动化测试框架设计》—第2章 2.7节使用CSV文件

2.7 使用CSV文件 CSV[1]的全称是Comma Separate Values,即以逗号为分隔符,每条记录占一行的一种文件格式.当然分隔符并不限制于逗号,因此其另一个名字叫做Character Separated Values.这种古老的文件格式早在20世纪60年代就已出现,被使用于IBM OS360上,远早于个人电脑时代的来临.时至今日,CSV文件依然顽强并且广泛地使用着,特别是在程序间交换数据的场合.例如,在某些ERP系统中,作为安装的一部分,在完成了二进制可执行文件的安装之后,需要

一个用servlet实现导出csv文件的实例

servlet 作者:李书鹏 tukeyli@sohu.com 关键字: Java Servlet CSV 本文实现了一个基于servlet技术的简单的csv文件导出的程序实例. 代码如下,其中setCsvData函数的作用是设置导出的数据,并将结果保存于Vector中,实际应用时可以任意扩展该函数: package common; import java.io.IOException;import java.io.PrintWriter;import java.util.Vector;impo

python自定义解析简单xml格式文件的方法

  这篇文章主要介绍了python自定义解析简单xml格式文件的方法,涉及Python解析XML文件的相关技巧,非常具有实用价值,需要的朋友可以参考下: 因为公司内部的接口返回的字串支持2种形式:php数组,xml;结果php数组python不能直接用,而xml字符串的格式不是标准的,所以也不能用标准模块解析.[不标准的地方是某些节点会的名称是以数字开头的],所以写个简单的脚步来解析一下文件,用来做接口测试. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

asp.net+js 实现无刷新上传解析csv文件的代码_javascript技巧

前阵子工作中用到,贴上代码,仅保留上传有关的代码,发现code其实很少. 上传页面html/js 复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xht

利用PHP生成CSV文件简单示例_php实例

前言 csv 文件其实和excel文件一样,都是表格类型.但PHP生成csv要比生成excel文件要简单的多,生成csv文件其实就是把以 , 号为分割符的字符串存成 .csv为扩展名的文件. 因为逻辑不难,具体请看下面的代码和注释. <?php /** * Created by PhpStorm. * User: chenyanphp@qq.com * Date: 2016/12/21 0021 * Time: 下午 12:08 */ // 头部标题 $csv_header = ['名称','性

利用PHP生成CSV文件简单示例

前言 csv 文件其实和excel文件一样,都是表格类型.但PHP生成csv要比生成excel文件要简单的多,生成csv文件其实就是把以 , 号为分割符的字符串存成 .csv为扩展名的文件. 因为逻辑不难,具体请看下面的代码和注释. <?php /** * Created by PhpStorm. * User: chenyanphp@qq.com * Date: 2016/12/21 0021 * Time: 下午 12:08 */ // 头部标题 $csv_header = ['名称','性