如何从R字符串中删除内部括号?

3

我正在R中处理字符串,这些字符串应该包含零个或一个括号对。如果有嵌套的括号,我需要删除内部的括号。下面是一个例子,我需要删除big bent nachos周围的括号,但不删除其他/外部的括号。

test <- c(
  "Record ID", 
  "What is the best food? (choice=Nachos)", 
  "What is the best food? (choice=Tacos (big bent nachos))", 
  "What is the best food? (choice=Chips with stuff)", 
  "Complete?"
) 

我知道可以使用 stringr 包的 str_remove_all() 方法来删除所有括号:

test |>
  stringr::str_remove_all(stringr::fixed(")")) |> 
  stringr::str_remove_all(stringr::fixed("("))

但我没有正则表达式技能来获取内部括号。我找到了一个与之接近的SO文章,但它删除了外部括号,我无法解开它以删除内部括号。


1
您是否也想删除括号内的内容?您只有一个内部括号还是多个内部括号?例如 here(a(b(c))),您想要 here(a) 还是 here(abc) - Onyambu
1
我只需要删除内部的 () 字符,而内容需要保留。 - itsMeInMiami
所以你需要有 here(abc) 吗?你最多只有一个嵌套的括号还是多个嵌套的括号? - Onyambu
1
一个简单的前瞻式正则表达式,用于匹配内部的括号: \(([^)(]*)\)(?=(?:[^)(]*\([^)(]*\))*[^)(]*\)) (替换为 $1) - 如果有嵌套,则使用递归正则表达式: (?:\G(?!^)|\()[^)(]*\K(\(((?>[^)(]+|(?1))*)\)) (替换为 $2) - 使用 gsub (perl=T) - bobble bubble
@onyambu,我认为上面关于Tacos的例子已经足够复杂了。 - itsMeInMiami
显示剩余2条评论
4个回答

3

好的,我来了。

test |>
  stringr::str_replace_all("(\\().*\\(", "\\1") |> # remove inner open brackets
  stringr::str_remove_all("\\)(?=.*\\))") # remove inner closed brackets

[1] "Record ID"                                       
[2] "What is the best food? (choice=Nachos)"          
[3] "What is the best food? (big bent nachos)"        
[4] "What is the best food? (choice=Chips with stuff)"
[5] "Complete?"

编辑

我修改了我的解决方案,以避免丢失文本:

test |>
  stringr::str_replace("\\((.*)\\(", "(\\1") |> # remove inner open brackets
  stringr::str_remove_all("\\)(?=.*\\))") # remove inner outer brackets

[1] "Record ID"                                            
[2] "What is the best food? (choice=Nachos)"               
[3] "What is the best food? (choice=Tacos big bent nachos)"
[4] "What is the best food? (choice=Chips with stuff)"     
[5] "Complete?" 

FYI:第3项缺少“choice=Tacos”的内容。 - Dave2e
哦,谢谢@Dave2e,我没有意识到。现在看看我的解决方案,我已经修复了它。一步到位,而且相当简单 :) 谢谢。 - Josh White
@JoshWhite 谢谢您提供的 Tidyverse 友好的解决方案!您有学习正则表达式的喜爱网站和/或书籍吗? - itsMeInMiami
不用道歉。对我来说,只是时间问题,我使用得越多,就会变得更好。所以继续练习吧! - Josh White

2
对于外层括号中有多个 (...) 的情况,我想了以下基于 前瞻 的解决方案。但它只检查外层右括号的情况。
test <- gsub("\\(([^)(]*)\\)(?=[^)(]*(?:\\([^)(]*\\)[^)(]*)*\\))", "\\1", test, perl=T)

请参阅 tio.run 上的此 R 演示regex101 上的模式演示(使用 \1 进行替换,捕获第一组)。
前瞻检查每个 (...),仅当其后跟随的是 (....)括号字符,直到 )
如果存在任意嵌套结构,通过 递归正则表达式 可以将第一层展开。
test <- gsub("(?:\\G(?!^)|\\()[^)(]*+\\K(\\(((?>[^)(]+|(?1))*)\\))", "\\2", test, perl=T)

再来一个tio.run上的R演示或者一个regex101演示(使用\2替换,即第二个组的捕获)
正则表达式部分 解释
(?:\G(?!^)|\() 匹配一个开括号,用于利用\G链接匹配
[^)(]*+\K 消耗任意数量括号,并使用\K重置开头
(\(((?>[^)(]+|(?1))*)\)) 匹配嵌套的括号(在php.net上的解释 ↗)。
它包含两个捕获组
• 第一个递归到(?1)
• 第二个捕获(内部内容)
这里的匹配项与开括号相连。没有检查外部的闭括号 )。 基于 \G 的思想也可以用于不使用递归,但效率略低。

1
假设最多只有一个嵌套的括号,我们可以使用 gsub() 方法来进行处理:
output <- gsub("\\(\\s*(.*?)\\s*\\(.*?\\)(.*?)\\s*\\)", "(\\1\\2)", test)
output

[1] "Record ID"                                       
[2] "What is the best food? (choice=Nachos)"          
[3] "What is the best food? (choice=Tacos)"           
[4] "What is the best food? (choice=Chips with stuff)"
[5] "Complete?"

数据:

test <- c(
  "Record ID", 
  "What is the best food? (choice=Nachos)", 
  "What is the best food? (choice=Tacos (big bent nachos))", 
  "What is the best food? (choice=Chips with stuff)", 
  "Complete?"
)

Tim,“我需要删除内部的一对”并没有暗示,至少在我看来,要删除()中的内容。 - Dave2e

1

这里提供了一种使用基本R中的gsub解决方案。为了便于阅读和调试,它被分解成两个步骤。

test <- c(
   "Record ID", 
   "What is the best food? (choice=Nachos)", 
   "What is the best food? (choice=Tacos (big bent nachos))", 
   "What is the best food? (choice=Chips with stuff)", 
   "Complete?"
) 

test <- gsub("(\\(.*)\\(", "\\1", test)
# ( \\(.*  ) - first group starts with '(' then zero or more characters following that first '('
#  \\(       - middle part look of a another '('

#  "\\1" replace the found group with the part from the first group

test <-gsub("\\)(.*\\))", "\\1", test)
#similer to first part
test

[1] "Record ID"                                            
[2] "What is the best food? (choice=Nachos)"               
[3] "What is the best food? (choice=Tacos big bent nachos)"
[4] "What is the best food? (choice=Chips with stuff)"     
[5] "Complete?"  

I need to delete the inner pair - Tim Biegeleisen
谢谢!这是一个很好的学习例子。你能推荐一些学习正则表达式的好地方吗?我喜欢看书。 - itsMeInMiami
1
@itsMeInMiami,这里有一个完整的教程:https://www.regular-expressions.info/tutorial.html - Dave2e
如果你来到迈阿密,午餐由我请客。 - itsMeInMiami

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接