本系列文章目錄
什么是 包裹(使用雙引號)?
包裹的概念是面向字段的,包裹起來的字段將會被視為一個整體。尤其當字段中包含一些特殊符號(如逗號、換行符、雙引號)時,如果不將這些字段包裹起來,則很有可能導致 CSV 文件解析發生錯誤。那么我們該如何包裹一個字段呢,通常將一個字段放置在雙引號("")之間,例如"ID",ID就是一個被包裹的字段。任何字段都可以使用雙引號("")將其包裹起來,並不存在任何限制。
字段中特殊符號的處理
根據上面的介紹,如果一個字段中包含特殊符號,那么在寫入時必須使用雙引號來包裹這個字段。有一點需要注意,C語言中字符串中的雙引號需要通過使用轉義符號來表示(\")
下面分別用逗號、換行符、雙引號來做示例
-
逗號:
fprintf(fp, "3,\"z,xc\",3.3\n");
-
換行符:
fprintf(fp, "4,\"qw\nas\",4.4\n");
-
雙引號:
fprintf(fp, "5,\"\"aszx\"\",5.5\n");
,第一個用作包裹字段,第二個雙引號才是實際的雙引號。
完整的程序如下:
// 2-1.c
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp = fopen("tmp.csv", "w+");
if (fp == NULL) {
fprintf(stderr, "fopen() failed.\n");
exit(EXIT_FAILURE);
}
fprintf(fp, "ID,Name,Points\n");
fprintf(fp, "1,qwe,1.1\n");
int id = 2;
char *name = "asd";
float point = 2.2;
fprintf(fp, "%d,%s,%f\n", id, name, point);
// special symbols
fprintf(fp, "3,\"z,xc\",3.3\n");
fprintf(fp, "4,\"qw\nas\",4.4\n");
fprintf(fp, "5,\"\"aszx\"\",5.5\n");
fclose(fp);
return 0;
}
運行程序,查看 CSV 文件內容,結果為:
字段開頭和結尾處的空格和制表符
CSV 文件中的字段中的開頭和結尾上,可能會存在空格或制表符,但是該如何處理呢?按照 RFC 4180 標准的規定,“空格被看作字段的一部分,不應當被忽略”。但是RFC 4180 並不是強制標准,因此某些實現中,空格和制表符會被截斷掉。因此 fprintf(fp, " 6,abc,6.6 \n");
寫入的字段可能是 6,abc,6.6
(按照 RFC 4180 標准) 或者是 6,abc,6.6
(空格被截掉)
然而,在 RFC 4180 標准中,並未說明空格字符若出現在被包裹的值之外如何處理,例如在 fprintf(fp, " \"7\",def,\"7.7\" \n");
語句中,如字段 \"7\"
,雖然7被包裹,但包裹之外的又有空格,因此目前標准中對這樣的空格該如何處理還沒有規定,可以保留也可以截掉。\"7.7\"
字段也面臨着同樣的問題。
想要將這種空格視為字段中有意義的數據,最省事的方法是將這些空格也包裹起來,例如 fprintf(fp, "\" 8\",ghi,\"8.8 \"\n");
語句中的 "\" 8\"
、\"8.8 \"
字段中,屬於字段的空格已被包裹。
完整的程序如下:
// 2-2.c
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp = fopen("tmp.csv", "w+");
if (fp == NULL) {
fprintf(stderr, "fopen() failed.\n");
exit(EXIT_FAILURE);
}
fprintf(fp, "ID,Name,Points\n");
fprintf(fp, "1,qwe,1.1\n");
int id = 2;
char *name = "asd";
float point = 2.2;
fprintf(fp, "%d,%s,%f\n", id, name, point);
// special symbols
fprintf(fp, "3,\"z,xc\",3.3\n");
fprintf(fp, "4,\"qw\nas\",4.4\n");
fprintf(fp, "5,\"\"aszx\"\",5.5\n");
// leading or trailing spaces
fprintf(fp, " 6,abc,6.6 \n");
fprintf(fp, " \"7\",def,\"7.7\" \n");
fprintf(fp, "\" 8\",ghi,\"8.8 \"\n");
fclose(fp);
return 0;
}
運行程序,查看 CSV 文件內容,結果為:
分隔符可能存在的問題
在某些國家(如德國、荷蘭)中,小數點不是點而是逗號,因此如果依然用逗號作分隔符,那么將無法正確表示。那么該在保證小數點是逗號前提下,如何避免CSV文件解析錯誤,存在兩種解決方法:
- 將所有包含小數點的數字包裹起來
- 使用分號而不是逗號作為分隔符
利用軟件進行配置
無論是開頭或結尾處的空格或制表符,還是分隔符的選擇,在一些功能強大的軟件中,這些其實都可以進行配置,下圖分別展示了在 Microsoft Excel、LibreOffice Calc中如何解析CSV文件的配置界面。
如果想要了解偏基礎的 C 語言讀取寫入 CSV 文件的內容,歡迎閱讀:[一] 基礎篇
如果想要了解進階的 C 語言讀取 CSV 文件的內容,歡迎閱讀:[三] 進階篇——讀取CSV