stringr 删除第 n 次出现的字符

stringr remove n-th occurence of a character

我知道这个问题之前已经被问过和回答过(例如 or ),但出于某种原因我无法使用相应的正则表达式解决方案。

我基本上想从字符串中删除某个短语的第 n 次出现,特别是在示例中我想删除第二次出现的“ab”,但我的尝试都没有成功。

我有一个解决方法,使用 str_locate_all,然后根据短语的位置执行 str_sub,但我希望使用 str_remove 的简单正则表达式解决方案或 str_replace 如果我想用某些东西替换这第二次出现。

text <- "abcdabef"

预期输出:

"abcdef"

我尝试过的无效解决方案(以及许多其他解决方案):

library(stringr)
str_remove_all(y, "(?:ab){2}")
str_remove_all(y, "(?:ab){1}.*(ab)")

要仅删除第二次出现,您需要使用

sub("(ab.*?)ab", "\1", "abcdabef")

要删除第 n 次出现,请在组后使用限制量词,其中唯一的 min 值应等于 n-1:

n <- 2
sub(paste0("((?:ab.*?){",n-1,"})ab"), "\1", "abcdabef", perl=TRUE)

:

您需要使用 sub 而不是 gsub,因为您只需要完成一次替换。

图案详情(当n=3):

  • ((?:ab.*?){2}) - 第 1 组 (</code>):出现两次 <code>ab 和除换行字符以外的任何零个或多个字符(因为我使用的是 perl=TRUE这里,如果需要多行匹配支持,在开头加上(?s)或者把.*?换成(?s:.*?))尽量少
  • ab - 一个 ab

如果你有带有特殊字符的任意字符串,你需要转义它们:

regex.escape <- function(string) {
  gsub("([][{}()+*^$|\\?.])", "\\\1", string)
}

word <- "a+(b)"
word <- regex.escape(word)
text <- "a+(b)1___a+(b)2___a+(b)3___a+(b)4"
n <- 3 # Let's remove the 3rd occurrence of a+(b)
sub(paste0("((?:", word, ".*?){",n-1,"})", word), "\1", text, perl=TRUE)
## => [1] "a+(b)1___a+(b)2___3___a+(b)4"

参见regex demo

另一种可能的解决方案,使用 stringr 而不使用 regex(它也适用于任何 n):

library(tidyverse)

text <-  "abcdabef"

n <- 2

str_locate_all(text, "ab") %>% .[[1]] %>% 
  when(n <= nrow(.) ~ `str_sub<-`(text, .[n, 1], .[n, 2], value = ""), ~ text)

#> [1] "abcdef"