From c3e4b6b21c2e0929acec525849e00be7677de33a Mon Sep 17 00:00:00 2001 From: Jan Marvin Garbuszus Date: Wed, 13 Nov 2024 22:57:55 +0100 Subject: [PATCH] [tables] escape specials in total row formula (#1181) * [tables] escape special characters in total row function * [misc] update NEWS again --- NEWS.md | 2 +- R/helper-functions.R | 10 ++++++++-- tests/testthat/test-write.R | 17 +++++++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/NEWS.md b/NEWS.md index a54b97262..41bd26bfa 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,7 +7,7 @@ ## Fixes * Previously rows that trigger scientific notation (e.g. `1e+05`) would cause issues, when matched against a non scientific version. [1170](https://github.com/JanMarvin/openxlsx2/pull/1170) -* When using `wb_add_data_table(..., total_row = TRUE)` the last row of the returned data tabled was replaced with the total row. This caused loss of data. [1179](https://github.com/JanMarvin/openxlsx2/issues/1179) +* When using `wb_add_data_table(..., total_row = TRUE)` the last row of the data table in the workbook was mistakenly overwritten with the total row formula, which should have been placed below the last row of the table. This caused loss of data. [1179](https://github.com/JanMarvin/openxlsx2/issues/1179) *************************************************************************** diff --git a/R/helper-functions.R b/R/helper-functions.R index 07b4bbbb6..26eea88db 100644 --- a/R/helper-functions.R +++ b/R/helper-functions.R @@ -982,11 +982,17 @@ clone_shared_strings <- function(wb_old, old, wb_new, new) { } +# In table names special characters must have a leading ' in front +# @params str a variable name +escape_specials <- function(str) { + gsub("([^a-zA-Z0-9\\s])", "'\\1", str, perl = TRUE) +} + known_subtotal_funs <- function(x, total, table, row_names = FALSE) { # unfortunately x has no row names at this point ncol_x <- ncol(x) + row_names - nms_x <- names(x) + nms_x <- escape_specials(names(x)) if (row_names) nms_x <- c("_rowNames_", nms_x) fml <- vector("character", ncol_x) @@ -994,7 +1000,7 @@ known_subtotal_funs <- function(x, total, table, row_names = FALSE) { lbl <- rep(NA_character_, ncol_x) if (isTRUE(total) || all(as.character(total) == "109") || all(total == "sum")) { - fml <- paste0("SUBTOTAL(109,", table, "[", names(x), "])") + fml <- paste0("SUBTOTAL(109,", table, "[", nms_x, "])") atr <- rep("sum", ncol_x) } else { diff --git a/tests/testthat/test-write.R b/tests/testthat/test-write.R index 7e4d8145f..6e670537a 100644 --- a/tests/testthat/test-write.R +++ b/tests/testthat/test-write.R @@ -1123,6 +1123,23 @@ test_that("writing total row works", { }) +test_that("escaping special characters works", { + df <- data.frame( + foo = rep("#Ref!", 5), + `1#1` = 1:5, + `@Two` = 1:5, + `A1-A3` = 1:5, + check.names = FALSE + ) + + wb <- wb_workbook()$add_worksheet()$add_data_table(x = df, total_row = TRUE) + + exp <- c("SUBTOTAL(109,Table1[foo])", "SUBTOTAL(109,Table1[1'#1])", + "SUBTOTAL(109,Table1['@Two])", "SUBTOTAL(109,Table1[A1'-A3])") + got <- unname(unlist(wb_to_df(wb, dims = "A7:D7", col_names = FALSE, show_formula = TRUE))) + expect_equal(exp, got) +}) + test_that("writing vectors direction with dims works", { # write vectors column or rowwise