Skip to content

Commit

Permalink
Add quote and escape arguments to writing functions
Browse files Browse the repository at this point in the history
Also change the default quote behavior of write_csv to "none" and write_excel to "all"

Fixes #653
Fixes #759
Fixes #844
Fixes #993
Fixes #1018
Fixes #1083
  • Loading branch information
jimhester committed May 6, 2021
1 parent 744fdb4 commit a6c2080
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 68 deletions.
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ export(write_rds)
export(write_tsv)
importFrom(R6,R6Class)
importFrom(hms,hms)
importFrom(lifecycle,deprecate_soft)
importFrom(lifecycle,deprecate_warn)
importFrom(lifecycle,deprecated)
importFrom(lifecycle,is_present)
Expand Down
6 changes: 6 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@

* All `read_*()` and `write_*()` functions gain a `num_threads` argument to control the number of processing threads they use (#1201)

* All `write_*()` and `format_*()` functions gain `quote` and `escape` arguments, to explicitly control how fields are quoted and how double quotes are escaped. (#653, #759, #844, #993, #1018, #1083)

* write_tsv() now defaults to `quote = "none"` (#993)

* write_excel_csv() now defaults to `quote = "all"` (#759)

## Additional features and fixes

* `read_rds()` can now read .Rds files from URLs (#1186)
Expand Down
2 changes: 1 addition & 1 deletion R/readr.R
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
"_PACKAGE"

## usethis namespace: start
#' @importFrom lifecycle deprecated is_present deprecate_warn
#' @importFrom lifecycle deprecated is_present deprecate_warn deprecate_soft
## usethis namespace: end
NULL
154 changes: 122 additions & 32 deletions R/write.R
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,12 @@
#' @param na String used for missing values. Defaults to NA. Missing values
#' will never be quoted; strings with the same value as `na` will
#' always be quoted.
#' @param quote_escape The type of escaping to use for quoted values, one of
#' `"double"`, `"backslash"` or `"none"`. You can also use `FALSE`, which is
#' equivalent to "none". The default is `"double"`, which is expected format for Excel.
#' @param quote_escape \Sexpr[results=rd, stage=render]{lifecycle::badge("deprecated")}
#' @param eol The end of line character to use. Most commonly either `"\n"` for
#' Unix style newlines, or `"\r\n"` for Windows style newlines.
#' @param path \Sexpr[results=rd, stage=render]{lifecycle::badge("deprecated")}
#' @return `write_*()` returns the input `x` invisibly.
#' @inheritParams vroom::vroom_write
#' @inheritParams read_delim
#' @references Florian Loitsch, Printing Floating-Point Numbers Quickly and
#' Accurately with Integers, PLDI '10,
Expand All @@ -69,14 +68,23 @@
#' setwd(.old_wd)
#' }
write_delim <- function(x, file, delim = " ", na = "NA", append = FALSE,
col_names = !append, quote_escape = "double", eol = "\n",
col_names = !append,
quote = c("needed", "all", "none"),
escape = c("double", "backslash", "none"),
eol = "\n",
num_threads = readr_threads(),
path = deprecated()) {
path = deprecated(),
quote_escape = deprecated()) {
if (is_present(path)) {
deprecate_warn("1.4.0", "write_delim(path = )", "write_delim(file = )")
file <- path
}

if (is_present(quote_escape)) {
deprecate_soft("2.0.0", "write_delim(quote_escape = )", "write_delim(escape = )")
escape <- quote_escape
}

stopifnot(is.data.frame(x))
check_column_types(x)

Expand All @@ -85,13 +93,13 @@ write_delim <- function(x, file, delim = " ", na = "NA", append = FALSE,
if (edition_first()) {
stream_delim(x, file,
delim = delim, col_names = col_names, append = append,
na = na, quote_escape = quote_escape, eol = eol
na = na, quote_escape = escape, eol = eol
)
return(invisible(x_out))
}
vroom::vroom_write(x, file,
delim = delim, col_names = col_names, append = append,
na = na, eol = eol, escape = quote_escape, num_threads = num_threads
na = na, eol = eol, quote = quote, escape = escape, num_threads = num_threads
)

invisible(x_out)
Expand All @@ -100,35 +108,53 @@ write_delim <- function(x, file, delim = " ", na = "NA", append = FALSE,
#' @rdname write_delim
#' @export
write_csv <- function(x, file, na = "NA", append = FALSE, col_names = !append,
quote_escape = "double", eol = "\n",
quote = c("needed", "all", "none"),
escape = c("double", "backslash", "none"),
eol = "\n",
num_threads = readr_threads(),
path = deprecated()) {
path = deprecated(),
quote_escape = deprecated()) {

if (is_present(path)) {
deprecate_warn("1.4.0", "write_csv(path = )", "write_csv(file = )")
file <- path
}

if (is_present(quote_escape)) {
deprecate_soft("2.0.0", "write_delim(quote_escape = )", "write_delim(escape = )")
escape <- quote_escape
}

write_delim(x, file,
delim = ",", na = na, append = append,
col_names = col_names, quote_escape = quote_escape, eol = eol, num_threads = num_threads
col_names = col_names, quote = quote, escape = escape, eol = eol, num_threads = num_threads
)
}

#' @rdname write_delim
#' @export
write_csv2 <- function(x, file, na = "NA", append = FALSE, col_names = !append,
quote_escape = "double", eol = "\n",
quote = c("needed", "all", "none"),
escape = c("double", "backslash", "none"),
eol = "\n",
num_threads = readr_threads(),
path = deprecated()) {
path = deprecated(),
quote_escape = deprecated()) {
if (is_present(path)) {
deprecate_warn("1.4.0", "write_csv2(path = )", "write_csv2(file = )")
file <- path
}

if (is_present(quote_escape)) {
deprecate_soft("2.0.0", "write_delim(quote_escape = )", "write_delim(escape = )")
escape <- quote_escape
}

x_out <- x
x <- change_decimal_separator(x, decimal_mark = ",")
write_delim(x, file,
delim = ";", na = na, append = append,
col_names = col_names, quote_escape = quote_escape, eol = eol, num_threads = num_threads
col_names = col_names, quote = quote, escape = escape, eol = eol, num_threads = num_threads
)

invisible(x_out)
Expand All @@ -137,15 +163,23 @@ write_csv2 <- function(x, file, na = "NA", append = FALSE, col_names = !append,
#' @rdname write_delim
#' @export
write_excel_csv <- function(x, file, na = "NA", append = FALSE,
col_names = !append, delim = ",", quote_escape = "double",
col_names = !append, delim = ",",
quote = "all",
escape = c("double", "backslash", "none"),
eol = "\n",
num_threads = readr_threads(),
path = deprecated()) {
path = deprecated(),
quote_escape = deprecated()) {
if (is_present(path)) {
deprecate_warn("1.4.0", "write_excel_csv(path = )", "write_excel_csv(file = )")
file <- path
}

if (is_present(quote_escape)) {
deprecate_soft("2.0.0", "write_delim(quote_escape = )", "write_delim(escape = )")
escape <- quote_escape
}

stopifnot(is.data.frame(x))
check_column_types(x)

Expand All @@ -157,13 +191,15 @@ write_excel_csv <- function(x, file, na = "NA", append = FALSE,
if (edition_first()) {
stream_delim(x, file, delim,
col_names = col_names, append = append,
na = na, bom = !append, quote_escape = quote_escape, eol = eol
na = na, bom = !append, quote_escape = escape, eol = eol
)
return(invisible(x_out))
}
vroom::vroom_write(x, file, delim,
col_names = col_names, append = append,
na = na, bom = !append, eol = eol, num_threads = num_threads
na = na, bom = !append,
quote = quote, escape = escape,
eol = eol, num_threads = num_threads
)

invisible(x_out)
Expand All @@ -172,15 +208,23 @@ write_excel_csv <- function(x, file, na = "NA", append = FALSE,
#' @rdname write_delim
#' @export
write_excel_csv2 <- function(x, file, na = "NA", append = FALSE,
col_names = !append, delim = ";", quote_escape = "double",
col_names = !append, delim = ";",
quote = "all",
escape = c("double", "backslash", "none"),
eol = "\n",
num_threads = readr_threads(),
path = deprecated()) {
path = deprecated(),
quote_escape = deprecated()) {
if (is_present(path)) {
deprecate_warn("1.4.0", "write_excel_csv2(path = )", "write_excel_csv2(file = )")
file <- path
}

if (is_present(quote_escape)) {
deprecate_soft("2.0.0", "write_delim(quote_escape = )", "write_delim(escape = )")
escape <- quote_escape
}

stopifnot(is.data.frame(x))
check_column_types(x)

Expand All @@ -192,7 +236,8 @@ write_excel_csv2 <- function(x, file, na = "NA", append = FALSE,

x[] <- lapply(x, output_column)
write_excel_csv(x, file, na, append, col_names, delim,
quote_escape = quote_escape,
quote = quote,
escape = escape,
eol = eol, num_threads = num_threads
)

Expand All @@ -202,17 +247,26 @@ write_excel_csv2 <- function(x, file, na = "NA", append = FALSE,
#' @rdname write_delim
#' @export
write_tsv <- function(x, file, na = "NA", append = FALSE, col_names = !append,
quote_escape = "double", eol = "\n",
quote = "none",
escape = c("double", "backslash", "none"),
eol = "\n",
num_threads = readr_threads(),
path = deprecated()) {
path = deprecated(),
quote_escape = deprecated()) {
if (is_present(path)) {
deprecate_warn("1.4.0", "write_tsv(path = )", "write_tsv(file = )")
file <- path
}

if (is_present(quote_escape)) {
deprecate_soft("2.0.0", "write_delim(quote_escape = )", "write_delim(escape = )")
escape <- quote_escape
}


write_delim(x, file,
delim = "\t", na = na, append = append, col_names =
col_names, quote_escape = quote_escape, eol = eol, num_threads = num_threads
col_names, quote = quote, escape = escape, eol = eol, num_threads = num_threads
)
}

Expand Down Expand Up @@ -241,38 +295,74 @@ write_tsv <- function(x, file, na = "NA", append = FALSE, col_names = !append,
#' cat(format_csv(df))
#' @export
format_delim <- function(x, delim, na = "NA", append = FALSE,
col_names = !append, quote_escape = "double", eol = "\n") {
col_names = !append,
quote = c("needed", "all", "none"),
escape = c("double", "backslash", "none"),
eol = "\n",
quote_escape = deprecated()) {
stopifnot(is.data.frame(x))
check_column_types(x)

if (is_present(quote_escape)) {
deprecate_soft("2.0.0", "write_delim(quote_escape = )", "write_delim(escape = )")
escape <- quote_escape
}

x[] <- lapply(x, output_column)
if (edition_first()) {
res <- stream_delim(df = x, file = NULL, delim = delim, col_names = col_names, append = append, na = na, quote_escape = quote_escape, eol = eol)
res <- stream_delim(df = x, file = NULL, delim = delim, col_names = col_names, append = append, na = na, quote_escape = quotequote_escape, eol = eol)
Encoding(res) <- "UTF-8"
return(res)
}
res <- vroom::vroom_format(x, delim = delim, eol = eol, col_names = col_names, na = na, escape = quote_escape)
res <- vroom::vroom_format(x, delim = delim, eol = eol, col_names = col_names, na = na, quote = quote, escape = escape)
Encoding(res) <- "UTF-8"
res
}

#' @export
#' @rdname format_delim
format_csv <- function(x, na = "NA", append = FALSE, col_names = !append, quote_escape = "double", eol = "\n") {
format_delim(x, delim = ",", na = na, append = append, col_names = col_names, quote_escape = quote_escape, eol = eol)
format_csv <- function(x, na = "NA", append = FALSE, col_names = !append,
quote = c("needed", "all", "none"),
escape = c("double", "backslash", "none"),
eol = "\n",
quote_escape = deprecated()) {
if (is_present(quote_escape)) {
deprecate_soft("2.0.0", "write_delim(quote_escape = )", "write_delim(escape = )")
escape <- quote_escape
}

format_delim(x, delim = ",", na = na, append = append, col_names = col_names, eol = eol, quote = quote, escape = escape)
}

#' @export
#' @rdname format_delim
format_csv2 <- function(x, na = "NA", append = FALSE, col_names = !append, quote_escape = "double", eol = "\n") {
format_csv2 <- function(x, na = "NA", append = FALSE, col_names = !append,
quote = c("needed", "all", "none"),
escape = c("double", "backslash", "none"),
eol = "\n",
quote_escape = deprecated()) {
if (is_present(quote_escape)) {
deprecate_soft("2.0.0", "write_delim(quote_escape = )", "write_delim(escape = )")
escape <- quote_escape
}

x <- change_decimal_separator(x, decimal_mark = ",")
format_delim(x, delim = ";", na = na, append = append, col_names = col_names, quote_escape = quote_escape, eol = eol)
format_delim(x, delim = ";", na = na, append = append, col_names = col_names, eol = eol, quote = quote, escape = escape)
}

#' @export
#' @rdname format_delim
format_tsv <- function(x, na = "NA", append = FALSE, col_names = !append, quote_escape = "double", eol = "\n") {
format_delim(x, delim = "\t", na = na, append = append, col_names = col_names, quote_escape = quote_escape, eol = eol)
format_tsv <- function(x, na = "NA", append = FALSE, col_names = !append,
quote = c("needed", "all", "none"),
escape = c("double", "backslash", "none"),
eol = "\n",
quote_escape = deprecated()) {
if (is_present(quote_escape)) {
deprecate_soft("2.0.0", "write_delim(quote_escape = )", "write_delim(escape = )")
escape <- quote_escape
}

format_delim(x, delim = "\t", na = na, append = append, col_names = col_names, eol = eol, quote = quote, escape = escape)
}

#' Preprocess column for output
Expand Down
Loading

0 comments on commit a6c2080

Please sign in to comment.