You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言读取带引号含逗号的CSV country列异常问题

解决带引号含逗号的CSV字段读取问题

问题根源

strtok 是按单一分隔符(这里是逗号)粗暴分割的工具,它无法识别CSV中双引号作为字段边界的规则——只要遇到逗号就会分割,导致带引号的"USA, UK"被拆成"USA和 UK"两个错误字段。

正确方案:手动逐字符解析

要正确处理带引号的CSV字段,必须手动扫描每行内容,区分引号内和引号外的逗号:引号内的逗号属于字段内容,不视为分隔符;引号外的逗号才是字段分隔符。

实现代码

以下是可直接使用的解析示例,包含字段提取函数和测试主逻辑:

#include <stdio.h>
#include <string.h>
#include <ctype.h>

// 从当前行指针提取下一个CSV字段,返回下一个字段的起始地址,字段内容存入buf
char* get_next_csv_field(char* line, char* buf, int buf_size) {
    if (!line || !buf || buf_size <= 0) return NULL;

    int in_quotes = 0;
    int buf_idx = 0;
    char* ptr = line;

    // 跳过字段开头的空白(可根据CSV格式选择保留或移除)
    while (isspace((unsigned char)*ptr)) ptr++;

    // 处理带引号的字段
    if (*ptr == '"') {
        in_quotes = 1;
        ptr++; // 跳过起始引号
    }

    while (*ptr != '\0') {
        if (in_quotes) {
            if (*ptr == '"') {
                // 处理转义引号(CSV中用""表示单个")
                if (*(ptr+1) == '"') {
                    if (buf_idx < buf_size - 1) {
                        buf[buf_idx++] = '"';
                    }
                    ptr += 2;
                    continue;
                }
                // 遇到结束引号,退出引号模式
                in_quotes = 0;
                ptr++;
                break;
            }
            // 引号内的普通字符直接存入缓冲区
            if (buf_idx < buf_size - 1) {
                buf[buf_idx++] = *ptr;
            }
            ptr++;
        } else {
            // 非引号模式下,遇到逗号或行尾结束当前字段
            if (*ptr == ',' || *ptr == '\n' || *ptr == '\r') {
                ptr++;
                break;
            }
            if (buf_idx < buf_size - 1) {
                buf[buf_idx++] = *ptr;
            }
            ptr++;
        }
    }

    // 移除字段末尾的空白(可选)
    while (buf_idx > 0 && isspace((unsigned char)buf[buf_idx-1])) {
        buf_idx--;
    }

    buf[buf_idx] = '\0';
    return ptr;
}

int main() {
    FILE* fp = fopen("your_file.csv", "r");
    if (!fp) {
        perror("无法打开文件");
        return 1;
    }

    char line[1024];
    while (fgets(line, sizeof(line), fp)) {
        char country[256];
        char* ptr = line;

        // 根据你的CSV列顺序,跳过前面的字段,直到country列
        // 示例:如果country是第2列,先跳过第1列
        // ptr = get_next_csv_field(ptr, country, sizeof(country));

        // 读取country字段
        ptr = get_next_csv_field(ptr, country, sizeof(country));
        printf("Country: %s\n", country);
    }

    fclose(fp);
    return 0;
}

代码说明

  1. 字段提取逻辑:get_next_csv_field会自动识别带引号的字段,忽略引号内的逗号;同时支持CSV标准的转义引号("")。
  2. 缓冲区处理:通过buf_size限制写入长度,避免缓冲区溢出,实际使用时可根据字段最大长度调整country和line的缓冲区大小。
  3. 列顺序适配:根据CSV实际列顺序,调整跳过的字段数,确保读取到正确的country列。

注意事项

  • 若CSV存在字段内换行的情况,需要额外处理(比如连续读取多行直到匹配到闭合引号),当前代码适用于单行字段的场景。
  • 不要依赖strtok、strtok_r这类简单分割工具处理带复杂格式的CSV,它们无法处理引号规则。

内容的提问来源于stack exchange,提问作者xlas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 06:53:19