str_replace_all迭代地替换命名的向量元素不是一次全部

时间:2018-01-09 13:20:40

标签: r str-replace stringr

我们说我有一个很长的字符串:pneumonoultramicroscopicsilicovolcanoconiosis。我想使用stringr::str_replace_all替换某些字母。根据文档,str_replace_all可以使用命名向量并用值替换名称。这适用于1次替换,但对于多次,它似乎迭代地进行,因此结果是替换prelast迭代。我不确定这是预期的行为。

library(tidyverse)
text_string = "developer"
text_string %>% 
  str_replace_all(c(e ="X")) #this works fine
[1] "dXvXlopXr"
text_string %>% 
  str_replace_all(c(e ="p", p = "e")) #not intended behaviour
[1] "develoeer"

期望的结果:

[1] "dpvploepr"

我通过介绍一个新角色来获得:

text_string %>% 
  str_replace_all(c(e ="X", p = "e", X = "p"))

这是一种可行的解决方法,但几乎不可能。这是一个错误还是我的期望错了?

我也希望能够同时用 n 其他字母替换 n 字母,最好使用两个向量(例如" old&# 34;和" new")或命名向量作为输入。

编辑

reprex以便于人类阅读

4 个答案:

答案 0 :(得分:2)

我正在开发一个处理问题类型的软件包。这比qdap::mgsub函数更安全,因为它不依赖于占位符。它完全支持正则表达式作为匹配和替换。您提供了一个命名列表,其中名称是要匹配的字符串,它们的值是替换值。

devtools::install_github("bmewing/mgsub")
library(mgsub)
mgsub("developer",list("e" ="p", "p" = "e"))
#> [1] "dpvploepr"

qdap::mgsub(c("e","p"),c("p","e"),"developer")
#> [1] "dpvploppr"

答案 1 :(得分:1)

我的解决方法是利用str_replace_all可以将函数作为替换的输入这一事实。

library(stringr)
text_string = "developer"
pattern <- "p|e"
fun <- function(query) {
    if(query == "e") y <- "p"
    if(query == "p") y <- "e"
    return(y)
}

str_replace_all(text_string, pattern, fun)

当然,如果你需要扩大规模,我建议使用更复杂的功能。

答案 2 :(得分:0)

函数可能有一个命令,所以在用s替换所有c后,用c替换所有s,只剩下c ... 试试这个:

long_string %>% str_replace_all(c(c ="X", s = "U"))  %>% str_replace_all(c(X ="s", U = "c"))

答案 3 :(得分:0)

意图是迭代行为。也就是说,我们可以使用自己的解决方法。我将使用character subsetting进行替换。

在命名向量中,我们可以按名称查找事物并获取每个名称的替换值。这就像同时进行所有替换一样。

rules <- c(a = "X", b = "Y", X = "a")
chars <- c("a", "a", "b", "X", "X")
rules[chars]
#>   a   a   b   X   X 
#> "X" "X" "Y" "a" "a"

所以在这里,在"a"向量中查找rules会让我们"X",有效地将"a"替换为"X"。其他角色也一样。

一个问题是没有匹配的名称会产生NA

rules <- c(a = "X", b = "Y", X = "a")
chars <- c("a", "Y", "Z")
rules[chars]
#>    a <NA> <NA> 
#>  "X"   NA   NA

为了防止NA出现,我们可以扩展规则以包含任何新字符,以便字符被其自身替换。

rules <- c(a = "X", b = "Y", X = "a")
chars <- c("a", "Y", "Z")
no_rule <- chars[! chars %in% names(rules)]
rules2 <- c(rules, setNames(no_rule, no_rule))
rules2[chars]
#>   a   Y   Z 
#> "X" "Y" "Z"

这就是以下功能背后的逻辑。

  • 将字符串分解为字符
  • 创建替换规则的完整列表
  • 查找替换值
  • 将字符串粘在一起
library(stringr)

str_replace_chars <- function(string, rules) {
  # Expand rules to replace characters with themselves 
  # if those characters do not have a replacement rule
  chars <- unique(unlist(strsplit(string, "")))
  complete_rules <- setNames(chars, chars)
  complete_rules[names(rules)] <- rules

  # Split each string into characters, replace and unsplit
  for (string_i in seq_along(string)) {
    chars_i <- unlist(strsplit(string[string_i], ""))
    string[string_i] <- paste0(complete_rules[chars_i], collapse = "")
  }
  string
}

rules <- c(a = "X", p = "e", e = "p")
string <- c("application", "developer")
str_replace_chars(string, rules)
#> [1] "XeelicXtion" "dpvploepr"