0

I’d be grateful for suggestions as to how to remap letters in strings in a map-specified way.

Suppose, for instance, I want to change all As to Bs, all Bs to Ds, and all Ds to Fs. If I do it like this, it doesn’t do what I want since it applies the transformations successively:

"abc" %>% str_replace_all(c(a = "b", b = "d", d = "f"))

Here’s a way I can do what I want, but it feels a bit clunky.

f <- function (str) str_c( c(a = "b", b = "d", c = "c", d = "f") %>% .[ strsplit(str, "")[[1]] ], collapse = "" )

"abc" %>% map_chr(f)

Better ideas would be much appreciated.

James.

P.S. Forgot to specify. Sometimes I want to replace a letter with multiple letters, e.g., replace all As with the string ZZZ.

P.P.S. Ideally, this would be able to handle vectors of strings too, e.g., c("abc", "gersgaesg", etc.)

James Bejon
  • 189
  • 5

2 Answers2

2

We could use chartr in base R

chartr("abc", "bdf", "abbbce")
#[1] "bdddfe"

Or a package solution would be mgsub which would also match and replace strings with number of characters greater than 1

library(mgsub)
mgsub("abbbce",  c("a", "b", "c"), c("b", "d", "f"))
#[1] "bdddfe"

mgsub("abbbce",  c("a", "b", "c"), c("ba", "ZZZ", "f"))
#[1] "baZZZZZZZZZfe"
akrun
  • 874,273
  • 37
  • 540
  • 662
  • Thanks so much. This would be brilliant, but I sometimes want to replace a letter with two letters, e.g., replace As with the string ZZZ. My bad. I should have specified that up front. – James Bejon Jun 15 '21 at 17:29
  • @JamesBejon then, it won't work. I was thinking that you need only a single letter replacement. Sometimes, we take examples literally – akrun Jun 15 '21 at 17:30
  • @JamesBejon can i ask why the `str_replace_all` is not working for you. It is a very compact code – akrun Jun 15 '21 at 17:30
  • Yep. It was a poorly specified question. Apologies. Thanks for the effort anyway. – James Bejon Jun 15 '21 at 17:31
  • @JamesBejon I understand the problem in the `str_replace` as it is recursively doing the replacement – akrun Jun 15 '21 at 17:39
  • 1
    Brilliant! mgsub is exactly what I'm after!! Thanks a bunch. – James Bejon Jun 15 '21 at 18:25
2

Maybe this is more elegant? It will also return warnings when values aren't found.

library(plyr)
library(tidyverse)
mappings <- c(a = "b", b = "d", d = "f")

str_split("abc", pattern = "") %>% 
  unlist() %>% 
  mapvalues(from = names(mappings), to = mappings) %>%
  str_c(collapse = "")

# The following `from` values were not present in `x`: d
# [1] "bdc"
yogevmh
  • 316
  • 1
  • 5