CSV解析必须遵循RFC 4180:双引号内换行合法、双引号内两个连续双引号表示一个字面双引号、逗号仅在非引号内为分隔符;需用专业库(如csv-parser)或严谨手写状态机,避免用std::getline按行/逗号简单分割,并注意Windows下\r\n字段内容与记录换行的区分及UTF-8编码读取。

CSV里带换行符和逗号,fgets或std::getline直接读会断行
Excel导出的CSV中,字段含换行符(\r\n)或逗号时,标准按行读取会把一个逻辑记录切成多段——因为Excel用双引号包裹含特殊字符的字段,比如:"Alice, Jr.",25,"New York\r\nOffice"。直接用std::getline按\n切,会在"New York\r\n处错误截断。
必须按RFC 4180规则解析:双引号内换行合法、双引号内两个连续双引号表示一个字面双引号、字段以逗号分隔但可被双引号包围。
- 别自己写状态机处理引号嵌套——容易漏掉
""转义或跨行边界 - 优先用成熟CSV解析库,如
csv-parser(header-only)或fast-cpp-csv-parser - 若必须手写,至少先跳过非引号开头的行首空白,再逐字符扫描,维护
in_quotes和escaped两个状态位
std::stringstream + std::getline 分割字段会崩在双引号里
常见错误是用std::getline(ss, field, ',')对单行字符串做字段切分,但这样完全无视双引号语义——遇到"a,b",c会拆成"a、b"、c三段,而不是预期的两段。
根本问题在于CSV不是“逗号分隔”,而是“逗号分隔,但引号内逗号不作为分隔符”。任何基于简单字符查找的分割都不可靠。
立即学习“C++免费学习笔记(深入)”;
- 不要对整行调用
std::getline(..., ','),哪怕你已确保该行不含换行符 - 如果用
csv-parser,它内部自动处理引号和转义,只需注册回调:reader.read_header(io::string_input_stream{csv_data}); - 若用
fast-cpp-csv-parser,注意它默认不支持跨行字段,需手动启用set_has_headers(true)并确认parse()返回值是否含完整记录
Windows换行\r\n混在字段里,std::getline默认只认\n会残留\r
Excel在Windows下导出CSV时,字段内的换行保存为\r\n,而std::getline默认以\n为分隔符,导致字段末尾多出\r字符(尤其在Linux/macOS编译运行时更明显)。
这不是编码问题,是行尾约定和字段内容的混淆。解析器必须区分“记录级换行”和“字段内换行”。
- 用
csv-parser时,它自动strip掉字段两端空白和\r,但需确认trim_fields = true(默认开启) - 手写解析时,在退出引号后、遇到逗号或行尾前,要主动跳过
\r(即检查if (c == '\r' && peek_next() == '\n') skip) - 避免用
.c_str()后传给C函数(如strtok),它们不识别\r\n组合,且破坏引号逻辑
中文GB2312/GBK乱码?不是CSV问题,是文件编码没指定
Excel导出CSV默认用系统本地编码(Windows简体中文通常是GBK),而C++标准库读文件时默认当UTF-8或locale编码处理。如果你用std::ifstream直接读,中文字段会变乱码——但这和逗号、换行解析完全无关,是编码层问题。
解决路径只有两条:要么转UTF-8保存CSV,要么在C++里按正确编码读取。
- 推荐让Excel导出为UTF-8:另存为 → CSV UTF-8(逗号分隔)→ 这样
std::ifstream配合std::codecvt_utf8(C++11)或C++20的std::text_encoding可用 - 若必须读GBK,Windows下可用
std::wifstream+std::codecvt_utf8_utf16配合MultiByteToWideChar(CP_ACP, ...)预转换,但跨平台麻烦 - 别指望
fstream::imbue设locale("Chinese")——它不可靠,且不影响CSV字段解析逻辑



















