如何单次遍历行字符串解析带双引号包裹的CSV文件
解析带双引号包裹字段的CSV文件解决方案
针对你遇到的三个核心问题,这里给出基于状态机的高效解析方案,直接解决行尾判断、字段间空白处理、字段内双引号转义的问题:
核心解决思路
采用状态机模式逐字符遍历,区分「非字段状态」和「字段内状态」,严格遵循CSV的引号转义规则:
- 非字段状态:跳过空格和逗号,直到遇到字段起始引号
- 字段内状态:处理普通字符,遇到连续双引号时保留单个,遇到单个双引号时结束当前字段
完整实现代码
#include <iostream> #include <vector> #include <string> #include <cctype> auto lines = std::vector<std::string>({ R"("ab","cd")", // 字段间无空格 R"("ab", "cd")", // 逗号后有空格 R"("ab" ,"cd")", // 逗号前有空格 R"("a""b" ,"c""d")" // 字段内包含转义双引号 }); auto parseQuotedCSVLine(const std::string& line, char wrapper) -> std::vector<std::string> { std::vector<std::string> chunks; std::string current_chunk; bool in_quoted_field = false; size_t i = 0; const size_t len = line.size(); while (i < len) { char c = line[i]; if (!in_quoted_field) { if (c == wrapper) { // 进入引号包裹的字段 in_quoted_field = true; i++; } else if (c == ',' || std::isspace(static_cast<unsigned char>(c))) { // 字段外的分隔符或空白直接跳过 i++; } else { // 忽略非引号包裹的字段(按需可扩展) i++; } } else { if (c == wrapper) { // 检查是否是转义双引号 if (i + 1 < len && line[i+1] == wrapper) { current_chunk += wrapper; i += 2; } else { // 当前字段结束,存入结果 chunks.push_back(current_chunk); current_chunk.clear(); in_quoted_field = false; i++; } } else { // 字段内普通字符直接追加 current_chunk += c; i++; } } } // 处理未闭合的字段(可选逻辑) if (in_quoted_field && !current_chunk.empty()) { chunks.push_back(current_chunk); } return chunks; } void printChunks(const std::vector<std::string>& chunks) { for (const auto& s : chunks) { std::cout << s << std::endl; } std::cout << "---" << std::endl; } int main() { for (const auto& line : lines) { auto chunks = parseQuotedCSVLine(line, '"'); printChunks(chunks); } return 0; }
针对三个问题的具体处理
可靠判断行尾:
遍历到字符串末尾时,若处于字段内状态,直接将当前未完成的字段存入结果(处理未闭合的异常情况);若处于非字段状态,说明所有字段已处理完毕。正常闭合的行中,最后一个字段的结束引号会触发状态切换,后续的空白字符会被跳过,自然完成行尾判断。处理相邻字段间的空白:
在非字段状态下,遇到空格、制表符等空白字符(通过std::isspace判断)直接跳过,仅在遇到字段起始引号时进入解析状态,彻底忽略字段间的冗余空白。字段内双引号保留为单个:
在字段内状态下,遇到引号时检查下一个字符:如果是连续的第二个引号,说明是CSV的转义规则,仅向当前字段添加一个引号并跳过下一个字符;如果是单个引号,则判定为字段结束。
测试输出
运行代码后,四个测试用例的输出依次为:
ab cd --- ab cd --- ab cd --- a"b c"d ---
内容的提问来源于stack exchange,提问作者DEKKER
相关产品推荐
相关产品推荐

