【问题标题】:gsub ) only if there is no (gsub ) 仅当没有 (
【发布时间】:2021-07-01 20:53:18
【问题描述】:

我在 R 中工作,并且仅在没有左括号时才尝试删除右括号。我在下面尝试过,它没有返回所需的输出。

test <- data.frame(t1 = c("Book (Pg 1)", "Website Online)", "Journal: 2018)"))
test

test$t2 <- ifelse(str_contains(test$t1, "("), test$t1, gsub("(", '', test$t1))

我希望将 test$t2 作为“Book (Pg1)”、“Website Online”、“Journal: 2018”返回

【问题讨论】:

  • 您需要使用双反斜杠转义特殊字符,例如 '\\('。见?regex

标签: r regex


【解决方案1】:

你也可以这样做:

sub("([(].*[)])|[)]", '\\1', test$t1)
[1] "Book (Pg 1)"    "Website Online" "Journal: 2018" 

【讨论】:

  • 先生。 Onyambu 我可以问为什么这个str_detect(c("(Website Online"), "[()]") 返回TRUE 但是如果我像你那样将每个括号分隔在一个括号中,它会返回FALSE?非常感谢您的回复。
  • @AnoushiravanR。我不明白你的意思。不过,您应该注意,除非您包含 fixed = TRUE,否则仅输入 ( 将不起作用,因为 ( 是一个元字符
  • @AnoushiravanR 你为什么要hsve [(][)] 这意味着你正试图在你的字符串中检测()。但是您的字符串中没有()。所以它会返回 false
  • @AnoushiravanR 是的,没错。你也可以简单地做\\(\\)。即转义两个字符,因为它们是元字符。要了解有关正则表达式含义的更多信息,请查看 wikipedia page on regex
  • @AnilGoyal 您的正则表达式只是从(upto)捕获所有内容,然后用捕获的组替换该部分。 ) 没有任何反应,因为它甚至不匹配。因此,您将获得与输入完全相同的输出。
【解决方案2】:

您不小心在 gsub() 中使用了左括号 ("(") 而不是右括号 (")")。此外,由于 () 是正则表达式元字符,您需要使用双反斜杠 ("\\") 将它们 转义 两次(一次用于 R 字符串,一次用于正则表达式)。

使用矢量化的grepl 作为base 解决方案,我们得到:

test$t2 <- ifelse(grepl("\\(", test$t1), test$t1, gsub("\\)", "", test$t1))

test 产生以下输出:

               t1             t2
1     Book (Pg 1)    Book (Pg 1)
2 Website Online) Website Online
3  Journal: 2018)  Journal: 2018

【讨论】:

  • 由于某种原因它给了我“1”,它应该是“书(Pg 1)”
  • 在运行test$t2 &lt;- ifelse(grepl("\\(", test$t1), test$t1, gsub("\\)", "", test$t1)) 之前,您是否通过test &lt;- data.frame(t1 = c("Book (Pg 1)", "Website Online)", "Journal: 2018)")) 重置了test?请注意,我使用的是 grepl() 而不是 str_contains()
  • 是的,由于某种原因 test$t1 的类型设置为整数,所以我将其更改为 as.character(test$t1) 并让它工作。感谢您的解决方案!
  • 乐于助人! :)
【解决方案3】:

更新的解决方案 感谢亲爱的@r2evens 的一个很好的提示,我们可以使用以下解决方案来节省rowwise 以获得更有效的解决方案:

test %>%
  mutate(t1 = if_else(grepl("\\(.*\\)", t1), t1, gsub("\\)", "", t1)))

              t1
1    Book (Pg 1)
2 Website Online
3  Journal: 2018

原解决方案 您也可以使用以下解决方案:

library(dplyr)
library(stringr)

test %>%
  rowwise() %>%
  mutate(t1 = case_when(
    all(str_detect(t1, c("\\(", "\\)"))) ~ t1,
    TRUE ~ str_replace(t1, "\\)", "")
  ))

# A tibble: 3 x 1
# Rowwise: 
  t1            
  <chr>         
1 Book (Pg 1)   
2 Website Online
3 Journal: 2018 

【讨论】:

  • rowwise() 在这里是不必要的反效率,它只是因为您使用的正则表达式才需要。将 all(... c("\\(","\\)")) 替换为 str_detect(t1, "\\(.*\\)") 并且逐行要求消失。 (坦率地说,stringrcase_when 在这里什么都不加,mutate(test, t2 = if_else(grepl("\\(.*\\)", t1), t1, gsub("\\)", "", t1))) 可以更短(或者只是grepl("\\(", t1) 的条件)。
  • 感谢亲爱的@r2evans 提供的有用提示。起初我试图删除rowwise,但并没有达到预期的结果。所以我很高兴知道为什么使用我原来的正则表达式我们需要它。至于case_when的选择,这里只是提高了可读性,我会在这里修改。真的谢谢。
  • 您需要rowwise,因为您使用all,这只是因为您要针对多种模式检查t1。将其减少为单一模式意味着您将不需要all,然后您可以删除rowwise。由于您的两个模式是文字(不是复杂的正则表达式),因此将它们组合起来很简单。
  • 意图是保留|的LHS并丢弃权利;如果找到 LHS,则不使用 RHS。如果未找到 LHS 而 RHS ,则丢弃 RHS。我认为"([(].*[)])","\\1" 很清楚,这是一个正则表达式-noop,现在我们在捕获括号之外附加|[)],所以如果LHS 未找到但RHS 是,\\1 为空。
  • 非常感谢亲爱的@r2evans 的详尽解释。这很棘手,但我现在明白了。
猜你喜欢
  • 2015-10-09
  • 2014-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多