11

In Python, you can specify string formats by name (this is of course a silly example):

parameters = {'label':'months', 'april':4,'may':5,'june':6}
formatstring = '%(label)s: %(april)d %(may)d %(june)d'
outputstring = formatstring % parameters

(The formatstring % parameters notation is the Python equivalent to do.call(sprintf,c(formatstring,as.list(parameters))) in R.)

The output string would be "months: 4, 5, 6". parameters is stored as a key-value pair (which might be called a dictionary, hashtable, or named list in various languages). The string format %(text)s allows you to reference which dictionary item (text) should be formatted in that slot.

Is there anything equivalent in R, or you have you found a good workaround?

hatmatrix
  • 42,883
  • 45
  • 137
  • 231
  • In your own interest you shouldn't assume that everyone able to help you with R understands Python. Explain what the Python code does. – Roland Jul 04 '13 at 17:47
  • this [question](http://stackoverflow.com/questions/13023274/how-to-do-printf-in-r) provides some useful background on "printf" in R. – TooTone Jul 04 '13 at 17:55
  • Thanks @Roland, I have added explanation. – hatmatrix Jul 04 '13 at 18:01
  • I would use the `brew` or `whisker` package for this; they're powerful templating tools. See [this question](http://stackoverflow.com/questions/16595621/error-safe-templating-with-brew-whisker) for an example. – baptiste Jul 04 '13 at 18:33
  • 1
    See also https://stackoverflow.com/q/46085274/149988 – jarmond Apr 18 '18 at 14:29

2 Answers2

13

1. Try gsubfn in the gsubfn package:

library(gsubfn)
parameters <- list(label = "months", april = 4, may = 5, june = 6)

gsubfn("\\w+", parameters, "label: april, may, june")

2. or try fn$ from the same package:

with(parameters, fn$identity("$label: $april, $may, $june"))

3. Here is a short infix function that transforms a format string and a list of parameters to a sprintf and then runs it:

library(gsubfn)
`%format%` <- function(fmt, list) {
    pat <- "%\\(([^)]*)\\)"
    fmt2 <- gsub(pat, "%", fmt)
    list2 <- list[strapplyc(fmt, pat)[[1]]]
    do.call("sprintf", c(fmt2, list2))
}

Use it like this:

> '%(label)s: %(april)d %(may)d %(june)d' %format% parameters
[1] "months: 4 5 6"
G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341
6

Although this is not built in to the system sprintf functions that R is using (see man printf for the system docs), it's easy enough to implement such a feature in R by replacing the named references with their respective positions -

sprintf_named <- function(fmt, ...) {
  args <- list(...)
  argn <- names(args)
  if(is.null(argn)) return(sprintf(fmt, ...))

  for(i in seq_along(args)) {
    if(argn[i] == "") next;
    fmt <- gsub(sprintf("%%{%s}", argn[i]), sprintf("%%%d$", i), fmt, fixed = TRUE)
  }

  do.call(sprintf, append(args, fmt, 0))
}

Here is an example usage:

sprintf_named("%{HIA}s!! %{RYLAH}s", RYLAH="Rock You Like a Hurricane", HIA="Here I Am")
## [1] "Here I Am!! Rock You Like a Hurricane"

We could also make it an infix:

`%format%` <- function(left, right) do.call(sprintf_named, append(right, left, 0))

"%{b}s %{a}s" %format% list(a='ya', b='boo')
## [1] "boo ya"
Neal Fultz
  • 9,282
  • 1
  • 39
  • 60