在R中的所有括号内提取信息

Tyl*_*ker 44 regex r

我有一个字符串以及在多个括号内提取信息的内容.目前,我可以使用下面的代码从最后一个括号中提取信息.我该怎么做才能提取多个括号并作为向量返回?

j <- "What kind of cheese isn't your cheese? (wonder) Nacho cheese! (groan) (Laugh)"                                                          
sub("\\).*", "", sub(".*\\(", "", j)) 
Run Code Online (Sandbox Code Playgroud)

目前的输出是:

[1] "Laugh"
Run Code Online (Sandbox Code Playgroud)

期望的输出是:

[1] "wonder" "groan"  "Laugh" 
Run Code Online (Sandbox Code Playgroud)

koh*_*ske 53

这是一个例子:

> gsub("[\\(\\)]", "", regmatches(j, gregexpr("\\(.*?\\)", j))[[1]])
[1] "wonder" "groan"  "Laugh" 
Run Code Online (Sandbox Code Playgroud)

我认为这应该运作良好:

> regmatches(j, gregexpr("(?=\\().*?(?<=\\))", j, perl=T))[[1]]
[1] "(wonder)" "(groan)"  "(Laugh)" 
Run Code Online (Sandbox Code Playgroud)

但结果包括括号......为什么?

这有效:

regmatches(j, gregexpr("(?<=\\().*?(?=\\))", j, perl=T))[[1]]
Run Code Online (Sandbox Code Playgroud)

感谢@MartinMorgan的评论.

  • 注意:这适用于矢量,但不适用于数据框列中的文本。 (5认同)

Das*_*son 21

使用stringr包我们可以减少一点.

library(stringr)
# Get the parenthesis and what is inside
k <- str_extract_all(j, "\\([^()]+\\)")[[1]]
# Remove parenthesis
k <- substring(k, 2, nchar(k)-1)
Run Code Online (Sandbox Code Playgroud)

@kohske使用regmatches,但我目前正在使用2.13,因此目前无法访问该功能.这增加了对stringr的依赖,但我认为它更容易使用,代码更清晰一些(好吧......就像使用正则表达式一样明确......)

编辑:我们也可以尝试这样的事情 -

re <- "\\(([^()]+)\\)"
gsub(re, "\\1", str_extract_all(j, re)[[1]])
Run Code Online (Sandbox Code Playgroud)

这个通过在正则表达式中定义标记的子表达式来工作.它提取与正则表达式匹配的所有内容,然后gsub仅提取子表达式内的部分.


Net*_*tle 7

我认为基本上有3种简单的方法可以提取R中的多个捕获组(不使用替换)。str_match_allstr_extract_allregmatches/gregexpr组合。

我喜欢@kohske的正则表达式,它的后面是一个开放的括号?<=\\(,后面是一个封闭的括号?=\\),并且在中间(懒惰地)抓取了所有内容,.+?换句话说(?<=\\().+?(?=\\))

使用相同的正则表达式:

str_match_all返回答案作为矩阵

str_match_all(j, "(?<=\\().+?(?=\\))")

     [,1]    
[1,] "wonder"
[2,] "groan" 
[3,] "Laugh" 

# Subset the matrix like this....

str_match_all(j, "(?<=\\().+?(?=\\))")[[1]][,1]
[1] "wonder" "groan"  "Laugh" 
Run Code Online (Sandbox Code Playgroud)

str_extract_all列表形式返回答案。

str_extract_all(j,  "(?<=\\().+?(?=\\))")
[[1]]
[1] "wonder" "groan"  "Laugh" 

#Subset the list...
str_extract_all(j,  "(?<=\\().+?(?=\\))")[[1]]
[1] "wonder" "groan"  "Laugh" 
Run Code Online (Sandbox Code Playgroud)

regmatches/gregexpr还返回答案作为列表。由于这是基本的R选项,因此有些人喜欢它。注意建议perl = TRUE

regmatches(j, gregexpr( "(?<=\\().+?(?=\\))", j, perl = T))
[[1]]
[1] "wonder" "groan"  "Laugh" 

#Subset the list...
regmatches(j, gregexpr( "(?<=\\().+?(?=\\))", j, perl = T))[[1]]
[1] "wonder" "groan"  "Laugh" 
Run Code Online (Sandbox Code Playgroud)

如果我误解了最流行的选项,希望SO社区可以更正/编辑此答案。


Jim*_*Jim 5

使用rex可以使这种类型的任务更简单一些.

matches <- re_matches(j,
  rex(
    "(",
    capture(name = "text", except_any_of(")")),
    ")"),
  global = TRUE)

matches[[1]]$text
#>[1] "wonder" "groan"  "Laugh"
Run Code Online (Sandbox Code Playgroud)