Пишите RFC4180 совместимые плоские файлы с менее агрессивным цитированием - PullRequest
2 голосов
/ 11 февраля 2020

При использовании write.table или write.csv в R двойные кавычки по умолчанию добавляются вокруг всех ненумерованных полей c независимо от того, требуются ли кавычки для правильного синтаксического анализа файла 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"

Обратите внимание на кавычки вокруг всех не числовых c полей.

Здесь 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 library и большинстве других совместимых с rfc4180 инструментов?

1 Ответ

2 голосов
/ 12 февраля 2020

Вы можете написать простую функцию для создания CSV, преобразовав фрейм данных в матрицу символов, избегая любых двойных кавычек, а затем заключая в кавычки любые строки, содержащие запятые или разрывы строк. Затем вы добавляете имена столбцов и пишете как csv с помощью writeLines

. Вы даже можете выбрать собственный разделитель, который будет работать, если он не является эзотерическим c, достаточным для того, чтобы его неправильно интерпретировали как регулярное выражение.

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.

...