Home > Enterprise >  Inserting a character before specified character in hierarchical manner in R
Inserting a character before specified character in hierarchical manner in R

Time:10-13

test.dat <- c("abcde", "abcXe", "abcdY", "abcXY")
test.want <- c("abcde", "abc1Xe", "abcd1Y", "abc1XY")

Suppose I wish to add "1" before "X" or "Y", and before "X" if both "X" and "Y" exist.

library(tidyverse)
case_when(
  str_detect(test.dat, "X") ~ str_replace(test.dat, "X", "1X"),
  str_detect(test.dat, "Y") ~ str_replace(test.dat, "Y", "1Y"),
  TRUE ~ as.character(test.dat)
)

This works but is there a better way to do this in concise manner? Perhaps in single str_replace?

How about if it was either "X" or "Y" whichever comes first?

stringr is preferable but I welcome any other methods. Thank you.

CodePudding user response:

You can use a look ahead with (?=X) for X and (?=Y) for Y and make the decission if there is an X with ifelse and grepl.

test.dat <- c("abcde", "abcXe", "abcdY", "abcXY", "abYcXY")

ifelse(grepl("X", test.dat)
     , sub("(?=X)", "1", test.dat, perl=TRUE)
     , sub("(?=Y)", "1", test.dat, perl=TRUE))
#[1] "abcde"   "abc1Xe"  "abcd1Y"  "abc1XY"  "abYc1XY"

or

sub("(?=X)|(?=Y)(?!.*X)", "1", test.dat, perl=TRUE)
#[1] "abcde"   "abc1Xe"  "abcd1Y"  "abc1XY"  "abYc1XY"

CodePudding user response:

You can use

test.dat <- c("abcde", "abcXe", "abcdY", "abcXY")
gsub("(XY?|Y)", "1\\1", test.dat)
# => [1] "abcde"  "abc1Xe" "abcd1Y" "abc1XY"

See the regex demo.

Here, (XY?|Y) matches and captures into Group 1 (\1) an X and an optional Y after it (with XY?), or (|) a Y char, and then all found matches are replaced with 1 and Group 1 value.

stringr version is

library(stringr)
str_replace_all(test.dat, "(XY?|Y)", "1\\1")

See the online R demo.

  • Related