regex 用gsub有条件替换可选组

emeijp43  于 2023-04-22  发布在  其他
关注(0)|答案(2)|浏览(126)

一个用户在How to italicize select words in a ggplot legend?中问我如何做到这一点,我对我的解决方案不满意。
我们的目标是在所有字符向量元素(除了给定的字符串)周围添加封闭的 *。让我们假设在这个例子中,这些字符向量元素总是在开头找到。我使用了一个可选的捕获第一组,然后包括第二组星号。当搜索的单词单独存在并且没有后续字符串时,问题就出现了。
我已经在代码中包含了所需的输出和一些尝试。

v <- head(rownames(mtcars))
## does also not work with (.*)?, nor with (.+) nor (.+)?
gsub("(Hornet |Valiant)?(.*)", "\\1\\*\\2\\*", v) 
#> [1] "*Mazda RX4*"         "*Mazda RX4 Wag*"     "*Datsun 710*"       
#> [4] "Hornet *4 Drive*"    "Hornet *Sportabout*" "Valiant**"

## desired output
ifelse(grepl("Valiant", v), v, gsub("(Hornet )?(.*)", "\\1\\*\\2\\*", v) )
#> [1] "*Mazda RX4*"         "*Mazda RX4 Wag*"     "*Datsun 710*"       
#> [4] "Hornet *4 Drive*"    "Hornet *Sportabout*" "Valiant"
mlnl4t2r

mlnl4t2r1#

可以与gsub一起使用的两个正则表达式引擎都不支持条件替换模式。
你可以用

v <- c("Mazda RX4","Mazda RX4 Wag","Datsun 710","Hornet 4 Drive","Hornet Sportabout","Valiant")
gsub("^(?:Hornet|Valiant)\\s*(*SKIP)(*F)|(.+)", "*\\1*", v, perl=TRUE)

参见regex demoR demo online
输出:

[1] "*Mazda RX4*"         "*Mazda RX4 Wag*"     "*Datsun 710*"       
[4] "Hornet *4 Drive*"    "Hornet *Sportabout*" "Valiant"

要确保第一个单词匹配为完整单词,请添加\b"^(?:Hornet|Valiant)\\b\\s*(*SKIP)(*F)|(.+)"
请确保使用perl=TRUE

  • Regex详细信息 *:
  • ^(?:Hornet|Valiant)\s*(*SKIP)(*F)-在字符串的开头匹配HornetValiant,然后匹配零个或多个空格,一旦匹配,丢弃并失败匹配,并从失败位置继续查找下一个匹配
  • |-或
  • (.+)-尽可能多地匹配一个或多个除换行符字符以外的字符(字符串的其余部分)。
5ktev3wc

5ktev3wc2#

不太深入,更黑客的答案,但更容易理解一个)
gsub只在字符串匹配提供的regex时执行替换。因此,要阻止*出现,您可以使regex停止匹配您的输入。
例如,在问题中提供的,你可以用负的lookahead来做。结果如下所示:

^(?!(?:Hornet|Valiant)$)(Hornet|Valiant)?(.*)$

演示here

相关问题