通过正则表达式根据字符串中的位置替换子字符串

5
假设我的字符串中有一个特定的模式,它出现了已知次数(n),我们不想对字符串的其余部分(特别是那些在这些模式之间的字符串)做任何假设。
此外,我有一个长度为n的向量(称为sf),我想用相应的元素修改每个模式的出现。因此,对于每个匹配,我想知道匹配已经命中了多少次?
我可以想到以下解决方案:
library(stringr)
sf <- letters[4:1]
ss <- "fdskjhf xx sd ss xx wwwe xx ss  xx sdsd"
#              ^^ 1st   ^^ 2nd  ^^ 3rd ^^ 4th
# add:         _sf[1]   _sf[2]  _sf[3] _sf[4]
# that is:     xx_d     xx_c    xx_b   xx_a


## add _sf[i] to the ith occurence of "xx" in ss
goal <- "fdskjhf xx_d sd ss xx_c wwwe xx_b ss  xx_a sdsd"

my_replacer_factory <- function(sf, start = 0) {
  cnt <- start
  function(el) {
    cnt <<- cnt + 1
    paste0(el, "_", rev(sf)[cnt])
  }
}

my_replacer <- my_replacer_factory(sf)
(res <- str_replace_all(ss, fixed("xx"), my_replacer))
# [1] "fdskjhf xx_d sd ss xx_c wwwe xx_b ss  xx_a sdsd"

all.equal(res, goal)
# [1] TRUE

这个似乎可以工作,但感觉容易出错,因为我依赖于str_replace_all从右边开始替换的事实。如果将来的实现中这种行为发生变化或并行化,该怎么办呢?
有没有其他方法可以实现这个目标?最好使用stringr函数?
类似的想法:
my_replacer_factory <- function(sf) {
  suffixes <- rev(sf)
  function(el) {
    on.exit(suffixes <<- suffixes[-1L], add = TRUE)
    paste0(el, "_", suffixes[1L])
  }
}
4个回答

5
一种方法是使用regmatches<-
sf <- letters[4:1]
ss <- "fdskjhf xx sd ss xx wwwe xx ss  xx sdsd"

regmatches(ss, gregexpr("xx", ss)) <- list(paste0("xx_", sf))
ss
#[1] "fdskjhf xx_d sd ss xx_c wwwe xx_b ss  xx_a sdsd"

#Alternative with look behind
regmatches(ss, gregexpr("(?<=xx)", ss, perl=TRUE)) <- list(paste0("_", sf))

4
你可以使用R中的strsplit编写自己的类似于stringr的函数。
str_replace_multi <- function(string, replace, replace_with) {
  sapply(strsplit(string, replace, fixed = TRUE), function(x) {
    paste0(paste0(head(x, -1), replace_with, collapse = ''), tail(x, 1))
  })
}

这样可以:
str_replace_multi(ss, 'xx', paste0('xx_', sf))
#> [1] "fdskjhf xx_d sd ss xx_c wwwe xx_b ss  xx_a sdsd"

它将在字符串上进行矢量化,以便您可以在向量中的多个字符串中替换多个目标。

2

这里的关键是 gsubfn 包,它使事情变得更容易。

# install.packages("gsubfn")
library(gsubfn)
p <- proto(fun = function(this, x) paste0(x, "_", count))
gsubfn("xx", p, ss)
[1] "fdskjhf xx_1 sd ss xx_2 wwwe xx_3 ss  xx_4 sdsd"

为了获得所期望的结果:
p <- proto(fun = function(this, x) paste0(x, "_", letters[stringr::str_count(ss, "xx") + 1 - count]))
gsubfn("xx", p, ss)
[1] "fdskjhf xx_d sd ss xx_c wwwe xx_b ss  xx_a sdsd"

虽然很简洁,但实际上是同样的想法,我们在某个地方保留一个“环境”,每次命中时计数器就会增加。使用gsubfn/proto,计数器已经免费添加了,而我之前需要自己保持更新。 - undefined

0

paste0(grep(

paste0(grep('xx', unlist(strsplit(ss, ' ')), value = TRUE, fixed = TRUE), '_', sf[1:4])
[1] "xx_d" "xx_c" "xx_b" "xx_a"

抱歉,但这完全没有回答我的问题。你假设令牌之间用空格 分隔(我明确说过不应该做出这样的假设)。其次,你只返回匹配项,而不是所需的整个字符串。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接