meier_flo
meier_flo

Reputation: 136

Replace 'from nth to the last' occurrence of word in string/text

This question has been asked previously but hasn't been answered to the asker's satisfaction.

Given the following string:

mystring <- "one fish two fish red fish blue fish"

The following function allows to replace the nth occurrence of a word in it:

replacerFn <- function(String, word, rword, n){
 stopifnot(n >0)
  pat <- sprintf(paste0("^((.*?\\b", word, "\\b.*?){%d})\\b",
           word,"\\b"), n-1)
  rpat <- paste0("\\1", rword)
  if(n >1) { 
    stringr::str_replace(String, pat, rpat)
   } else {
    stringr::str_replace(String, word, rword)
    }
 }


 replacerFn(mystring, "fish", "dog", 1)
 #[1] "one dog two fish red fish blue fish"
 replacerFn(mystring, "fish", "dog", 2)
 #[1] "one fish two dog red fish blue fish"
 replacerFn(mystring, "fish", "dog", 3)
 #[1] "one fish two fish red dog blue fish"
 replacerFn(mystring, "fish", "dog", 4)
 #[1] "one fish two fish red fish blue dog"

How do we have to adjust this function to replace the nth to last occurrence of the word?

2nd to last:

"one fish two dog red dog blue dog"

3rd to last:

"one fish two fish red dog blue dog"

and so on ...?

I tried things like str_replace_all or adjusting the regex part {1,} but without success.

Thanks for your help!

Upvotes: 4

Views: 145

Answers (3)

ThomasIsCoding
ThomasIsCoding

Reputation: 101189

You can use grep within your function replacerFn, i.e.,

replacerFn <- function(String, word, rword, n) {
  v <- unlist(strsplit(String,split = " "))
  v[grep(word,v)[n:length(v)]] <- rword
  return(paste0(v,collapse = " "))
}

Upvotes: 1

prosoitos
prosoitos

Reputation: 7327

Your function is rather complex, with conditions. An alternative approach is to split the string into a character vector of individual words, apply stringr functions on it, then join it back into a single string:

library(stringr)

replace_function <- function(string, word, rword, n) {
  vec <- unlist(strsplit(string, " "))
  vec[str_which(vec, word)[n]] <- rword
  str_c(vec, collapse = " ")
}

replace_function(mystring, "fish", "dog", 1)
[1] "one dog two fish red fish blue fish"

replace_function(mystring, "fish", "dog", 2)
[1] "one fish two dog red fish blue fish"

Now, you can modify this function very easily to replace the nth element from the end, using rev():

replace_end_function <- function(string, word, rword, n) {
  vec <- unlist(strsplit(string, " "))
  vec[rev(str_which(vec, word))[n]] <- rword
  str_c(vec, collapse = " ")
}

replace_end_function(mystring, "fish", "dog", 1)
[1] "one fish two fish red fish blue dog"

replace_end_function(mystring, "fish", "dog", 2)
[1] "one fish two fish red dog blue fish"

Edit (my bad for thinking that "nth to last" meant "nth from last"):

To replace the nth to the last element:

replace_end_function <- function(string, word, rword, n) {
  vec <- unlist(strsplit(string, " "))
  vec[str_which(vec, word)[n:length(str_which(vec, word))]] <- rword
  str_c(vec, collapse = " ")
}

replace_end_function(mystring, "fish", "dog", 1)
[1] "one dog two dog red dog blue dog"

replace_end_function(mystring, "fish", "dog", 2)
[1] "one fish two dog red dog blue dog"

replace_end_function(mystring, "fish", "dog", 3)
[1] "one fish two fish red dog blue dog"

replace_end_function(mystring, "fish", "dog", 4)
[1] "one fish two fish red fish blue dog"

Upvotes: 1

akrun
akrun

Reputation: 887008

Here is an easier option with gsubfn

library(gsubfn)
replacerFn2 <- function(String, word, rword, n) {

  p <- proto(fun = function(this, x) if (count >= n) rword else x) 
   gsubfn(word, p, String)
 }

replacerFn2(mystring, "fish", "dog", 2)
#[1] "one fish two dog red dog blue dog"

replacerFn2(mystring, "fish", "dog", 3)
#[1] "one fish two fish red dog blue dog"
replacerFn2(mystring, "fish", "dog", 4)
#[1] "one fish two fish red fish blue dog"

Upvotes: 3

Related Questions