8

I tried

> str_replace("abcdef", c("b", "d"), c(b="B", d="D"))
[1] "aBcdef" "abcDef"

hoping for

[1] "aBcDef"

How can we replace each pattern with a specific replacement with one function call to stringr::str_replace?

stevec
  • 41,291
  • 27
  • 223
  • 311
  • 1
    You could do with a `chartr` solution as indicated in the answers here (such solution is mentioned at the beginning of the question I linked). On the other hand, packages are open source and the code is accessible on GitHub - so you can check the source code and perhaps even copy/paste it without the need for installing a package. – arg0naut91 Feb 08 '20 at 17:20

4 Answers4

17

The chartr() solution was new to me too, but I wanted to replace single characters with multiple. Eventually found a stringr (v1.4.0) solution that's quite simple. In fact it's in the help page, once it dawned that this calls for str_replace_all.

# one approach that both: answers the original question with stringr
str_replace_all("abcdef", c(b="B", d="D"))
[1] "aBcDef"

# and answers a more general question
str_replace_all("abcdef", c(b="BB", d="DDD"))
[1] "aBBcDDDef"
Scrope
  • 386
  • 2
  • 5
  • to make this a little clearer, the character vector structure is c("pattern you want to find" = "replacement value"). the `stringr::str_replace_all` function allows you to pass multiple patterns to apply to a single string using this approach: `str_replace_all("Hello World", c("World" = "my Darling", "H\\w+" = "Goodbye"))` – daneshjai Jan 08 '22 at 16:22
14

With str_replace an option is to wrap with reduce2

library(stringr)
library(purrr)
reduce2(c('b', 'd'), c('B', 'D'),  .init = 'abcdef', str_replace)
#[1] "aBcDef"

Or with anonymous function call

reduce2(c('b', 'd'), c('B', 'D'),  .init = 'abcdef',
         ~ str_replace(..1, ..2, ..3))
#[1] "aBcDef"
akrun
  • 874,273
  • 37
  • 540
  • 662
  • Thanks Akrun. Do you know if there's a way using *only* `stringr` and base R functions? – stevec Feb 08 '20 at 19:46
  • 1
    @stevec that would be a `for` loop `for(i in seq_along(v1)) v1 <- str_replace(v1, pat[i], repl[i])` – akrun Feb 08 '20 at 19:51
  • 1
    @stevec The `str_replace` function behavior is different than you expect i.e for multple pattern, replacement, it does the pairwise corresponding replacement instead of updating the original string. `reduce2` doesn't have `Reduce2` replacement in `base R`. Only way is `for` loop (other options I am not aware of) – akrun Feb 08 '20 at 20:00
  • 2
    @akrun I want you to know that for years I've been finding your answers all over SO, and they always seem to be correct, helpful, and clear. Thank you. – DaveRGP Nov 30 '22 at 22:52
4

This matches each character and if it equals b it replaces it with B, if it equals d it replaces it with D and otherwise it leaves it as is.

library(gsubfn)
gsubfn(".", list(b="B", d="D"), "abcdef")
## [1] "aBcDef"

These also work:

gsubfn("[bd]", list(b="B", d="D"), "abcdef")
## [1] "aBcDef"

gsubfn("[bd]", toupper, "abcdef")
## [1] "aBcDef"

# only needs base R
chartr("bd", "BD", "abcdef")
## [1] "aBcDef"
G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341
1

I would put it in a pipe

str_replace('abcdef', 'b', 'B') %>% str_replace(., 'd', 'D')
MarBlo
  • 4,195
  • 1
  • 13
  • 27