将函数应用于R中gsub中的反向引用

时间:2014-08-26 13:02:45

标签: r backreference

我是R的新手,我坚持使用似乎无法正常工作的反向引用。在:

gsub("\\((\\d+)\\)", f("\\1"), string)

它正确地抓住了括号之间的数字但是没有应用(正确定义的,否则正常工作)函数f来替换数字 - >它实际上是字符串" \ 1"传递给f。

我错过了什么或只是R不处理这个?如果是这样,任何想法我怎么能做类似的事情,即在飞行中应用一个功能"在我正在解析的文本中括号之间出现的(实际上很多)数字?

非常感谢你的帮助。

4 个答案:

答案 0 :(得分:5)

R无法通过gsub直接将匹配功能应用于匹配项。您实际上必须提取匹配,转换值,然后替换值。使用regmatches函数可以轻松实现这一点。例如

x<-"(990283)M (31)O (29)M (6360)M"

f<-function(x) {
    v<-as.numeric(substr(x,2,nchar(x)-1))
    paste0(v+5,".1")
}

m <- gregexpr("\\(\\d+\\)", x)
regmatches(x, m) <- lapply(regmatches(x, m), f)
x
# [1] "990288.1M 36.1O 34.1M 6365.1M"

当然,您可以f做任何您喜欢的事情,只要确保它对矢量友好。当然,你可以将它包装在你自己的函数中

gsubf <- function(pattern, x, f) {
    m <- gregexpr(pattern, x)
    regmatches(x, m) <- lapply(regmatches(x, m), f)
    x   
}
gsubf("\\(\\d+\\)", x, f)

请注意,在这些示例中我们不使用捕获组,我们只是抓住整个匹配。有一些方法可以提取捕获组,但它们有点混乱。如果你想提供一个需要这种提取的例子,我可能会想出更高级的东西。

答案 1 :(得分:1)

要在具有正则表达式的替换功能中使用回调,可以使用gsubfnstringr函数。

在它们之间进行选择时,请注意stringr基于ICU正则表达式引擎,并且与gsubfn一起使用,您可以使用默认的 TCL (如果R安装具有{ {1}}功能,否则为默认TRE)或PCRE(如果传递了tcltk参数)。

还要注意,perl=TRUE允许访问匹配对象中的所有捕获组,而gsubfn仅允许操纵整个匹配项。因此,对于str_replace_all,正则表达式应类似于str_replace_all,其中仅当1+个数字用(?<=\()\d+(?=\))(括起来时才被匹配,< / p>

对于),您可以使用stringr

str_replace_all

通过library(stringr) string <- "(990283)M (31)O (29)M (6360)M" ## Callback function to increment found number: f <- function(x) { as.integer(x) + 1 } str_replace_all(string, "(?<=\\()\\d+(?=\\))", function(m) f(m)) ## => [1] "(990284)M (32)O (30)M (6361)M" ,传递gsubfnperl=TRUE可以使用环顾四周,并且只需修改整个匹配项即可:

backref=0

如果模式中有多个组,请删除gsubfn("(?<=\\()\\d+(?=\\))", ~ f(m), string, perl=TRUE, backref=0) ## => [1] "(990284)M (32)O (30)M (6361)M" 并在回调函数声明中枚举组值参数:

backref=0

答案 2 :(得分:0)

这适用于多种不同的替代品。

text="foo(200) (300)bar (400)foo (500)bar (600)foo (700)bar"

f=function(x)
{
  return(as.numeric(x[[1]])+5)
}
a=strsplit(text,"\\(\\K\\d+",perl=T)[[1]]

b=f(str_extract_all(text,perl("\\(\\K\\d+")))

paste0(paste0(a[-length(a)],b,collapse=""),a[length(a)])  #final output
#[1] "foo(205) (305)bar (405)foo (505)bar (605)foo (705)bar"

答案 3 :(得分:0)

这是一种通过在替换参数中稍微调整stringr::str_replace()的方式,只需使用lambda公式作为替换参数,然后不使用""\\1"而是使用..1引用捕获的组,因此您的gsub("\\((\\d+)\\)", f("\\1"), string)将变成str_replace2(string, "\\((\\d+)\\)", ~f(..1)),或者在这种简单情况下变成str_replace2(string, "\\((\\d+)\\)", f)

str_replace2 <- function(string, pattern, replacement, type.convert = TRUE){
  if(inherits(replacement, "formula"))
    replacement <- rlang::as_function(replacement)
  if(is.function(replacement)){
    grps_mat <- stringr::str_match(string, pattern)[,-1, drop = FALSE]
    grps_list <- lapply(seq_len(ncol(grps_mat)), function(i) grps_mat[,i])
    if(type.convert) {
      grps_list <- type.convert(grps_list, as.is = TRUE) 
      replacement <- rlang::exec(replacement, !!! grps_list)
      replacement <- as.character(replacement)
    } else {
      replacement <- rlang::exec(replacement, !!! grps_list)
    }
  }
  stringr::str_replace(string, pattern, replacement)
}

str_replace2(
  "foo (4)",
  "\\((\\d+)\\)", 
  sqrt)
#> [1] "foo 2"

str_replace2(
  "foo (4) (5)",
  "\\((\\d+)\\) \\((\\d+)\\)", 
  ~ sprintf("(%s)", ..1 * ..2))
#> [1] "foo (20)"

reprex package(v0.3.0)于2020-01-24创建