2

在 R 中使用write.tableorwrite.csv时,默认情况下会在所有非数字字段周围添加双引号,而不管正确解析 csv 文件是否实际需要引号。

以 Python 脚本为例:

import csv
f_out=open("pytest.csv", "w")
wri = csv.writer(f_out, delimiter=',')
wri.writerow(['c_numeric', 'c_str', 'c_str_spec'])
wri.writerow([11, "r1c2", "r1c3 nothing special"])
wri.writerow([21, "r2c2", "r2c3,with delim"])
wri.writerow([31, "r3c2", "r3c3\nwith carriage return"])
wri.writerow([41, "r4c2", "r3c3\"with double quote"])
f_out.close()

这会将以下内容输出到pytest.csv

c_numeric,c_str,c_str_spec
11,r1c2,r1c3 nothing special
21,r2c2,"r2c3,with delim"
31,r3c2,"r3c3
with carriage return"
41,r4c2,"r3c3""with double quote"

这是我所期望的,并且遵循 Excel 也将输出的内容。

现在让我们使用 R 处理这个文件,并使用和不使用引号编写:

df <- read.csv("pytest.csv")
write.csv(df, 'Rtest.csv', row.names=FALSE)
write.csv(df, 'Rtest_NQ.csv', row.names=FALSE, quote=FALSE)

这里是Rtest.csv

"c_numeric","c_str","c_str_spec"
11,"r1c2","r1c3 nothing special"
21,"r2c2","r2c3,with delim"
31,"r3c2","r3c3
with carriage return"
41,"r4c2","r3c3""with double quote"

请注意所有非数字字段周围的引号。

这里是Rtest_NQ.csv

c_numeric,c_str,c_str_spec
11,r1c2,r1c3 nothing special
21,r2c2,r2c3,with delim
31,r3c2,r3c3
with carriage return
41,r4c2,r3c3"with double quote

此文件在技术上已损坏,因为任何 csv 阅读器都无法读取它——因此不是一个好的选择。

我的问题:R 中是否有任何兼容 rfc4180 的编写器可以像 Excel 或 python csv 库以及大多数其他 rfc4180 兼容工具那样编写?

4

1 回答 1

2

您可以编写一个简单的函数来构造 csv,方法是将数据帧转换为字符矩阵,转义任何双引号,然后引用任何包含逗号或换行符的字符串。然后,您添加列名并写为 csvwriteLines

您甚至可以选择自定义分隔符,只要它不够深奥而不会被误解为正则表达式,它就可以工作。

write_unquoted <- function(df, path, delim = ",")
{
  regexp <- paste0(delim, "|\n")
  x <- as.matrix(df) 
  x[grep("\"", x)] <- paste0("\"", gsub("\"", "\"\"", x[grep("\"", x)]), "\"")
  x[grep(regexp, x)]  <- paste0("\"", x[grep(regexp, x)], "\"")
  x <- c(paste0(colnames(x), collapse = delim), apply(x, 1, paste0, collapse = delim))
  writeLines(x, path)
}

因此,如果我们从您的示例开始:

df
#>   c_numeric c_str                 c_str_spec
#> 1        11  r1c2       r1c3 nothing special
#> 2        21  r2c2            r2c3,with delim
#> 3        31  r3c2 r3c3\nwith carriage return
#> 4        41  r4c2     r3c3"with double quote

我们做

write_unquoted(df, "my.csv")

我们可以看到它忠实地存储了数据框:

identical(read.csv("my.csv"),  df)
#> [1] TRUE

如果我们查看生成的 csv,它看起来像这样:

c_numeric,c_str,c_str_spec
11,r1c2,r1c3 nothing special
21,r2c2,"r2c3,with delim"
31,r3c2,"r3c3
with carriage return"
41,r4c2,"r3c3""with double quote"

也就是说,仅在需要时引用。

我不知道是否有任何反例表明这种简单方法不兼容 RFC4180。

于 2020-02-11T21:47:02.050 回答