- CSV是逗号分隔值(comama separated value)的缩写,也有一说是字符分隔值。因为分隔符也可以是其他字符。
- 当csv某个字段中包含换行(CRLF)、双引号、逗号(分隔符)时,整个字段必须用双引号括起来。例如:
"aaa","b CRLF
bb","ccc" CRLF
zzz,yyy,xxx
- 当csv某个字段用双引号括起来且字段中内容中还包含双引号时,必须在该引号前面再添加一个双引号进行转义。
"aaa","b""bb","ccc"
关于CSV的RFC文档: https://tools.ietf.org/html/rfc4180
下面是一个简单的示例代码(c语言),仅仅是个demo,写的并不是很完善
// gcc main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CSV_DELIM ","
#define CSV_QUOTE "\""
#define CSV_QUOTE_CHAR '"'
#define CSV_CRLF "\r\n"
#define CSV_SPECIAL_CHARS ",\"\r\n"
// 注意:
// 1, 这里假设escape buf足够大,不会出现溢出问题
// 2, 并未考虑原始字符串就已经被双引号括起来的场景,如: "abc"这种可能已经不需要再加双引号了
int escape_csv_string(char* escape_buf, const char* raw_data)
{
int found_special_char = 0; // 标识是否发现了双引号、逗号、CRLF中的任意一个特殊字符
const char* first_non_quote_char = NULL; // 记录“后面第一个字符的位置
const char* special_chars = CSV_SPECIAL_CHARS;
int buf_used_len = 0;
const char* tmp_val = raw_data;
while (*tmp_val)
{
if (!found_special_char) // 只要发现一个特殊字符,就需要在该字段前后加". 后面就不需要再查找特殊字符了
{
for (const char* c = special_chars; *c; ++c)
{
if (*tmp_val == *c)
{
// 发现特殊字符,首先在整个字符串前面加一个",并设置标志位,以便整体遍历结束后在尾部也追加一个"
strcat(escape_buf, CSV_QUOTE);
++buf_used_len;
found_special_char = 1;
break;
}
}
}
// 如果特殊字符是",直接追加写进去两个""
if (*tmp_val == CSV_QUOTE_CHAR)
{
if (NULL != first_non_quote_char)
{
// 发现"后,首先将上一个"之后到这个"之前的部分拷贝到buf中
strncpy(escape_buf + buf_used_len, first_non_quote_char, tmp_val - first_non_quote_char);
buf_used_len += tmp_val - first_non_quote_char;
escape_buf[++buf_used_len] = '\0';
}
buf_used_len += 2;
strcat(escape_buf, CSV_QUOTE);
strcat(escape_buf, CSV_QUOTE);
first_non_quote_char = NULL;
}
else
{
// 记录第一个非"字符的位置
if (NULL == first_non_quote_char)
first_non_quote_char = tmp_val;
}
tmp_val++;
}
if (found_special_char)
{
if (NULL != first_non_quote_char) // 最后一个字符是"
{
strcat(escape_buf, first_non_quote_char);
}
strcat(escape_buf, CSV_QUOTE);
}
else // 说明字符串中没有特殊字符
{
strcat(escape_buf, raw_data);
}
return 0;
}
int main(int argc, char* argv[])
{
while (1)
{
printf("\nplsese input a string:\n");
char input[1024] = {0};
scanf("%s", input);
char output[1024] = {0};
escape_csv_string(output, input);
printf("After escape: s\n", output);
}
return 0;
}