当出现次数未知时,如何用反向引用进行替换?

How to do a replace with backreferences, when the number of occurences is unknown?

为了对 Bookdown 生成的 .tex 文件进行一些更正,我需要在引用中使用 , 替换出现的 }{,即

s <- "Text.\autocites{REF1}{REF2}{REF3}. More text \autocites{REF4}{REF5} and \begin{tabular}{ll}"

应该变成

"Text.\autocites{REF1,REF2,REF3}. More text \autocites{REF4,REF5} and \begin{tabular}{ll}

因为我需要保留引用,所以我尝试查看反向引用,但我似乎做错了,因为事先不知道要匹配的组数。另外,我不能做 stringr::str_replace_all(s, "\}\{", ","),因为 }{ 也出现在文档的其他地方。

到目前为止,我最好的方法是使用回溯仅在 \autocites 之后发生时才进行替换,但是我无法获得正确的反向引用和分组:

stringr::str_replace_all(s, "(?<=\\autocites\{)([:alnum:]+)(\}\{)", "\1,")
[1] "Text.\autocites{REF1,REF2}{REF3}. More text \autocites{REF4,REF5} and \begin{tabular}{ll}"

stringr::str_replace_all(s, "(?<=\\autocites\{)([:alnum:]+)((\}\{)([:alnum:]+))*", "\1,\4")
[1] "Text.\autocites{REF1,REF3}. More text \autocites{REF4,REF5} and \begin{tabular}{ll}"

我可能遗漏了一些非常明显的方法,所以我希望有人能提供帮助。

很酷的问题 - 我学会了 str_replace 的新技巧。您可以使 return 值成为一个函数,并将该函数应用于您选择的字符串。

replace_brakets <- function(str) {
  str_replace_all(str, "\}\{", ",")
}

s %>% str_replace_all("(?<=\\autocites\{)([:alnum:]+\}\{)+", replace_brakets)
# [1] "Text.\autocites{REF1,REF2,REF3}. More text \autocites{REF4,REF5} and \begin{tabular}{ll}"

pat 匹配

  • autocites 后跟
  • }结尾的最短字符串是
  • 后跟字符串结尾或非{

然后使用 gsubfn 将其中出现的每个 }{ 替换为逗号。它使用公式表示法来表示替换函数——函数体在 ~ 的 RHS 上,因为函数体包含 ..1 参数被认为是 ... 。它不使用零宽度先行或后行。

library(gsubfn)

pat <- "(autocites.*?\}($|[^{]))"
gsubfn(pat, ~ gsub("}{", ",", ..1, fixed = TRUE), s)

给予:

[1] "Text.\autocites{REF1,REF2,REF3}. More text \autocites{REF4,REF5} and \begin{tabular}{ll}"

变化

上面显示的正则表达式的一个小的简化是从 pat 中删除外括号,而是在 gsubfn 中指定 backref = 0。这告诉它将整个匹配传递给函数。我们可以像上面那样使用 ..1 来指定参数,但是因为我们知道必须只传递一个参数,所以我们可以在函数体中将它指定为 x 。任何变量名都会像它假定任何自由变量是一个参数那样做。输出与上面相同。

pat2 <- "autocites.*?\}($|[^{])"
gsubfn(pat2, ~ gsub("}{", ",", x, fixed = TRUE), s, backref = 0)