简单的csv文件解析

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

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
目录
相关文章
|
数据处理 开发者 Python
Python 高级编程:深入解析 CSV 文件读取
在Python中,读取CSV文件是数据处理的重要环节。本文介绍了两种高效方法:一是利用pandas库的`read_csv`函数,将CSV文件快速转换为DataFrame对象,便于数据操作;二是通过csv模块的`csv.reader`按行读取CSV内容。此外,还涉及了如何选取特定列、解析日期格式、跳过指定行以及分块读取大文件等高级技巧,帮助开发者更灵活地处理各种CSV文件。参考链接:<https://www.wodianping.com/app/2024-10/48782.html>。
738 7
|
存储 Python
【可定制、转换时间戳】解析nc文件,并保存为csv文件
【可定制、转换时间戳】解析nc文件,并保存为csv文件
1366 4
|
分布式计算 Java 大数据
MaxCompute产品使用合集之大数据计算MaxCompute外部表映射了oss中的csv文件,看到"\N"被解析为"N",是什么原因
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
Java 开发工具 git
java解析CSV文件三种方法(openCSV)
java解析CSV文件三种方法(openCSV)
835 0
|
数据采集
【详细步骤解析】爬虫小练习——爬取豆瓣Top250电影,最后以csv文件保存,附源码
【详细步骤解析】爬虫小练习——爬取豆瓣Top250电影,最后以csv文件保存,附源码
1127 0
|
Java Maven
CSV 文件解析
<p>介绍</p> <p>    在很多时候,数据是以CSV文件格式存放的。在提取CSV数据时,我们借助javacsv这个开源工具来处理,还是比较方便。</p> <p><br></p> <p>javacsv in pom.xml of Maven<br></p> <p></p> <pre code_snippet_id="387236" snippet_file_name="bl
2143 0
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
973 140
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
1625 29

推荐镜像

更多
  • DNS