在R中以分层方式在指定字符之前插入一个字符

aio*_*orr 3 regex r stringr

test.dat <- c("abcde", "abcXe", "abcdY", "abcXY", "abYcXY", "abcYX")
test.want <- c("abcde", "abc1Xe", "abcd1Y", "abc1XY", "abYc1XY", "abcY1X")
Run Code Online (Sandbox Code Playgroud)

假设我希望在“X”或“Y”之前添加“1”,并且如果“X”和“Y”都存在,则仅在“X”之前添加“ 1”。

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)
)
Run Code Online (Sandbox Code Playgroud)

这是可行的,但是有没有更好的方法以简洁的方式做到这一点?也许是单人str_replace

如果是“X”或“Y”(先到者为准),第二种情况怎么样?

test.dat <- c("abcde", "abcXe", "abcdY", "abcXY", "abYcXY", "abcYX")
test.want <- c("abcde", "abc1Xe", "abcd1Y", "abc1XY", "ab1YcXY", "abc1YX")
Run Code Online (Sandbox Code Playgroud)

stringr 是更好的选择,但我欢迎任何其他方法。谢谢。

GKi*_*GKi 5

(?=X)您可以使用forX(?=Y)for进行预判,并在存在with和Y的情况下做出决定。Xifelsegrepl

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

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" "abcY1X"  "Y1XXdY"
Run Code Online (Sandbox Code Playgroud)

或者

sub("(?=X)|(?=Y(?!.*X))", "1", test.dat, perl=TRUE)
#[1] "abcde"   "abc1Xe"  "abcd1Y"  "abc1XY"  "abYc1XY" "abcY1X"  "Y1XXdY"
Run Code Online (Sandbox Code Playgroud)

where(?=X)匹配之前的位置X(?=Y(?!.*X))匹配之前的位置,之后的任何位置都Y没有。X

如果不仅应该使用第一个命中:

ifelse(grepl("X", test.dat)
     , gsub("(?=X)", "1", test.dat, perl=TRUE)
     , gsub("(?=Y)", "1", test.dat, perl=TRUE))
#[1] "abcde"   "abc1Xe"  "abcd1Y"  "abc1XY"  "abYc1XY" "abcY1X"  "Y1X1XdY"
Run Code Online (Sandbox Code Playgroud)

或者

gsub("(?=X)|(^[^X]*)(?=Y(?!.*X))", "\\11", test.dat, perl=TRUE)
#[1] "abcde"   "abc1Xe"  "abcd1Y"  "abc1XY"  "abYc1XY" "abcY1X"  "Y1X1XdY"
Run Code Online (Sandbox Code Playgroud)

并匹配XY以先到者为准:

sub("(?=X)|(?=Y)", "1", test.dat, perl=TRUE)
#sub("(?=X|Y)", "1", test.dat, perl=TRUE) #Alternative
#sub("(?=[XY])", "1", test.dat, perl=TRUE) #Alternative
#[1] "abcde"   "abc1Xe"  "abcd1Y"  "abc1XY"  "ab1YcXY" "abc1YX"  "1YXXdY"
Run Code Online (Sandbox Code Playgroud)