From ~/R/D/r-devel/R/src/library/tcltk/R/Tk.R

Inside .Tcl.args() function, there’s a val2string() utility function and that has had — here wrapped in its own function —

escape1 <- function(x) {
    ## quoting hell...
    x <- gsub("\\\\", "\\\\\\\\", as.character(x))
    x <- gsub("\"",  "\\\\\"", as.character(x))
    x <- gsub("\\[", "\\\\[",  as.character(x)) # (polymode completely confused)
    x <- gsub("\\$", "\\\\$",  as.character(x))
}

Note how emacs polymode cannot deal with the above: It does not close the R chunk, does auto-indentation (wrongly!), and when I try to type in this paragraph here (which it thinks is still R code, strange things happen such as the point jumping to the beginning of the line … YIKES !#!! )

[of course, rstudio has no problem here …]


Now a faster and easier version – using fixed = TRUE should be better in both respect, human readability and speed:

escapeF <- function(x) {
        x <- gsub("\\", "\\\\", as.character(x), fixed=TRUE)
        x <- gsub("\"",  "\\\"", x, fixed=TRUE)
        x <- gsub("[",   "\\[" , x, fixed=TRUE)
        x <- gsub("$",   "\\$",  x, fixed=TRUE)
}

Now try things :

tbsl <- c("foo bar one pair \\ and two \\\\ and three \\\\\\ - finish!",
          "Now odd numbers plus doublequote 1: \"  3: \\\"  5: \\\\\" - and finis",
          "pairs with open bracket [: 1 \\[ 2 \\\\[ - fin!",
          "and $: 1 \\$  2 \\\\$,  3 \\\\\\$")
writeLines(tbsl)
## foo bar one pair \ and two \\ and three \\\ - finish!
## Now odd numbers plus doublequote 1: "  3: \"  5: \\" - and finis
## pairs with open bracket [: 1 \[ 2 \\[ - fin!
## and $: 1 \$  2 \\$,  3 \\\$

Ok, and how does it work?

x1 <-  escape1(tbsl)
writeLines(x1)
## foo bar one pair \\ and two \\\\ and three \\\\\\ - finish!
## Now odd numbers plus doublequote 1: \"  3: \\\"  5: \\\\\" - and finis
## pairs with open bracket \[: 1 \\\[ 2 \\\\\[ - fin!
## and \$: 1 \\\$  2 \\\\\$,  3 \\\\\\\$

and with the “faster” function:

xF <-  escapeF(tbsl)
if(isTRUE(eq <- all.equal(x1, xF))) {
    cat("They are the same -- fine!\n") 
} else {
    cat("They differ -- not good:\n")
    print(eq)
    cat("The second ('xF') is:\n")
    writeLines(xF)
}
## They are the same -- fine!

Also, is there anything strange about "\n" ? The package tools (and utils ?) use several times sub("\n", "\n ", chr) and similar with_out_ a fixed=TRUE specification.

str(lic <- Filter(function(.)nchar(.) >= 1, capture.output(licence())))
##  chr [1:15] "This software is distributed under the terms of the GNU General" ...
str(txt <- paste(lic, collapse="\n"))
##  chr "This software is distributed under the terms of the GNU General\nPublic License, either Version 2, June 1991 or"| __truncated__
iset <- 1:(2^11)
system.time(for(i in iset) t2  <- gsub("\n", "\n   ", txt))
##    user  system elapsed 
##   0.031   0.000   0.032
system.time(for(i in iset) t2F <- gsub("\n", "\n   ", txt, fixed=TRUE))
##    user  system elapsed 
##   0.008   0.000   0.007
## the 'fixed=TRUE' one is  3--4 x faster
identical(t2, t2F)
## [1] TRUE
writeLines(t2)
## This software is distributed under the terms of the GNU General
##    Public License, either Version 2, June 1991 or Version 3, June 2007.
##    The terms of version 2 of the license are in a file called COPYING
##    which you should have received with
##    this software and which can be displayed by RShowDoc("COPYING").
##    Version 3 of the license can be displayed by RShowDoc("GPL-3").
##    Copies of both versions 2 and 3 of the license can be found
##    at https://www.R-project.org/Licenses/.
##    A small number of files (the API header files listed in
##    R_DOC_DIR/COPYRIGHTS) are distributed under the
##    LESSER GNU GENERAL PUBLIC LICENSE, version 2.1 or later.
##    This can be displayed by RShowDoc("LGPL-2.1"),
##    or obtained at the URI given.
##    Version 3 of the license can be displayed by RShowDoc("LGPL-3").
##    'Share and Enjoy.'

Last but not least, even though it’s far from perfect, let’s give tribute to the microbenchmark package and to use some graphics visualizing speed differences:

require(microbenchmark)
## Loading required package: microbenchmark
str(ltxt <- c(rep(tbsl,5), x1, lic))
##  chr [1:39] "foo bar one pair \\ and two \\\\ and three \\\\\\ - finish!" ...
mb <- microbenchmark(esc_1 = escape1(ltxt),
                     esc_F = escapeF(ltxt), times = 250)
mb
## Unit: microseconds
##   expr     min      lq      mean   median      uq      max neval cld
##  esc_1 157.957 161.057 178.79764 162.2485 165.952 3019.538   250   b
##  esc_F  18.859  19.837  30.28704  21.0710  21.774 2223.847   250  a
plot(mb, log = "y", notch=TRUE)