【问题标题】:Variable-length negative look-behind for replacing list delimiters and the string end用于替换列表分隔符和字符串结尾的可变长度负后视
【发布时间】:2020-06-11 04:52:15
【问题描述】:

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

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]"

【问题讨论】:

  • 你的替换模式是关闭的,你只有1个捕获组,所以你必须使用\\1,而不是\\2
  • 太棒了!我认为每组括号代表一个组。只剩下可变长度方面。

标签: r regex negative-lookbehind


【解决方案1】:

在您的替换模式中,\2 指的是不存在的组 #2。 (?&lt;!...) 是一个否定的lookbehind,与捕获组不同,它不会强制正则表达式引擎为其匹配的值分配任何特殊的内存缓冲区。

您必须使用\1,而不是\2

要解决后视中的可变宽度模式,您可以使用带有 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 #2R demo online

模式 #1 详细信息

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

模式#2

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

或者,如果您可以使用 stringr 并且您知道位数小于某个值,例如 100,您可以利用此 constrained-width lookbehind ICU 库功能:

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

这里,(?&lt;!\[\d{1,100}]) 匹配字符串中的位置,该位置不是紧跟在 [ 前面的位置,1 到 100 位数字,然后是 ]

【讨论】:

  • 谢谢!但是,一个小问题是即使在现有索引之后,此代码也会将[0] 添加到最后一个值。
  • @syre 是的,这是罪魁祸首,因为$ 是一个零宽度断言,并且在这里测试了两次结束位置。
  • @syre 我有一个两步解决方法,请参阅this R demo
  • @syre 如果您可以使用stringr 并且您知道位数小于某个值,例如100,您可以使用stringr::str_replace_all(s, "(?&lt;!\\[\\d{1,100}])(;|$)", "[0]\\1")
  • @syre ] 在字符类之外不是特殊的正则表达式元字符。 ] 只能在 MSVC C++ 正则表达式 ECMAScript 风格中转义。
猜你喜欢
  • 2020-03-11
  • 2021-10-06
  • 1970-01-01
  • 1970-01-01
  • 2014-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多