Запись плоских файлов, совместимых с RFC4180, с менее агрессивным цитированием
Когда используешь write.table
или write.csv
в R двойные кавычки добавляются вокруг всех нечисловых полей по умолчанию, независимо от того, действительно ли кавычки требуются для правильного анализа файла 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?
1 ответ
Вы можете написать простую функцию для создания CSV, преобразовав фрейм данных в символьную матрицу, избегая любых двойных кавычек и заключая в кавычки любые строки, содержащие запятые или разрывы строк. Затем вы добавляете имена столбцов и пишете как csv сwriteLines
Вы даже можете выбрать собственный разделитель, который будет работать до тех пор, пока он недостаточно эзотеричен, чтобы его можно было неправильно интерпретировать как регулярное выражение.
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.