用于替换列表定界符和字符串结尾的可变长度否定后视

Variable-length negative look-behind for replacing list delimiters and the string end

我希望在分隔值字符串(包括最后一个)中缺少索引的值之后插入索引。

s <- "Dee, DP(Dee, D. P.)[1];Uppala, SM(Uppala, S. M.);Simmons, AJ(Simmons, A. J.);Kobayashi, S(Kobayashi, S.)[2];Andrae, U(Andrae, U.)"
gsub("(?<!\[\d\])(;|$)", "\[0\]\2", s, perl=TRUE)

这段代码让我缺少定界符:

"Dee, DP(Dee, D. P.)[1];Uppala, SM(Uppala, S. M.)[0]Simmons, AJ(Simmons, A. J.)[0]Kobayashi, S(Kobayashi, S.)[2];Andrae, U(Andrae, U.)[0]"

代码类似地处理最后一个值已经有索引的情况:

s <- "Dee, DP(Dee, D. P.)[1];Uppala, SM(Uppala, S. M.);Simmons, AJ(Simmons, A. J.);Kobayashi, S(Kobayashi, S.)[2];Andrae, U(Andrae, U.)[3]"

这次捐赠(仍缺少分隔符):

"Dee, DP(Dee, D. P.)[1];Uppala, SM(Uppala, S. M.)[0]Simmons, AJ(Simmons, A. J.)[0]Kobayashi, S(Kobayashi, S.)[2];Andrae, U(Andrae, U.)[3]"

我需要找回丢失的分隔符,例如第一种情况:

"Dee, DP(Dee, D. P.)[1];Uppala, SM(Uppala, S. M.)[0];Simmons, AJ(Simmons, A. J.)[0];Kobayashi, S(Kobayashi, S.)[2];Andrae, U(Andrae, U.)[0]"

此外,我希望代码也能处理多于一位数的索引,即 10、100 等(可变长度),例如:

s <- "Dee, DP(Dee, D. P.)[10];Uppala, SM(Uppala, S. M.);Simmons, AJ(Simmons, A. J.);Kobayashi, S(Kobayashi, S.)[2];Andrae, U(Andrae, U.)"

s <- "Dee, DP(Dee, D. P.)[10];Uppala, SM(Uppala, S. M.);Simmons, AJ(Simmons, A. J.);Kobayashi, S(Kobayashi, S.)[2];Andrae, U(Andrae, U.)[3]"

在您的替换模式中,</code> 指的是不存在的第 2 组。 <code>(?<!...) 是一个负面回顾,与捕获组不同,它不会强制正则表达式引擎为其匹配值分配任何特殊内存缓冲区。

您必须使用 </code>,而不是 <code>

要解决后视中的可变宽度模式,您可以使用带有 SKIP-FAIL 动词的 PCRE 模式的两步方法:

s <- gsub("\[\d+];(*SKIP)(*F)|(;)", "[0]\1", s, perl=TRUE)
sub("(?s)^(?!.*\[\d+]$)(.*)", "\1[0]", s, perl=TRUE)

regex demo #1 / regex demo #2 and the R demo online

模式 #1 详细信息

  • \[\d+];(*SKIP)(*F) - [, 1+ 位, ] 然后 ;; (*SKIP)(*F) 从整体匹配内存缓冲区中丢弃此匹配文本,并继续从失败的位置搜索正则表达式模式
  • | - 或
  • (;) - 第 1 组(替换模式中的 </code>):一个 <code>; 字符。

模式#2

  • (?s) - 转换 dotall 模式,以便 . 可以匹配 TRE 正则表达式中的任何字符(由 sub 使用而没有 perl=TRUE
  • ^ - 字符串开头
  • (?!.*\[\d+]$) - 否定前瞻,确保字符串
  • 末尾没有 [、1+ 位和 ]
  • (.*) - 所有字符串都在第 1 组中捕获。

或者,如果您可以使用 stringr 并且您知道位数少于某个值,例如 100,您可以利用此 constrained-width 后视 ICU图书馆特色:

stringr::str_replace_all(s, "(?<!\[\d{1,100}])(;|$)", "[0]\1")

这里,(?<!\[\d{1,100}])匹配字符串中不紧跟[的位置,1到100位,然后是].