web-dev-qa-db-fra.com

Extraire les informations à l'intérieur de toutes les parenthèses dans R

J'ai une chaîne de caractères et quoi extraire les informations à l'intérieur de plusieurs parenthèses. Actuellement, je peux extraire les informations de la dernière parenthèse avec le code ci-dessous. Comment pourrais-je le faire pour qu'il extrait plusieurs parenthèses et retourne comme vecteur?

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

La sortie actuelle est:

[1] "Laugh"

La sortie souhaitée est:

[1] "wonder" "groan"  "Laugh" 
42
Tyler Rinker

Voici un exemple:

> gsub("[\\(\\)]", "", regmatches(j, gregexpr("\\(.*?\\)", j))[[1]])
[1] "wonder" "groan"  "Laugh" 

Je pense que cela devrait bien fonctionner:

> regmatches(j, gregexpr("(?=\\().*?(?<=\\))", j, Perl=T))[[1]]
[1] "(wonder)" "(groan)"  "(Laugh)" 

mais les résultats incluent des parenthèses ... pourquoi?

Cela marche:

regmatches(j, gregexpr("(?<=\\().*?(?=\\))", j, Perl=T))[[1]]

Merci @MartinMorgan pour le commentaire.

50
kohske

En utilisant le package stringr, nous pouvons réduire cela un peu.

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

@kohske utilise des regmatches mais j'utilise actuellement la 2.13, donc je n'ai pas accès à cette fonction pour le moment. Cela ajoute la dépendance à stringr mais je pense que c'est un peu plus facile à travailler et le code est un peu plus clair (enfin ... aussi clair que l'utilisation d'expressions régulières peut être ...)

Edit: Nous pourrions également essayer quelque chose comme ça -

re <- "\\(([^()]+)\\)"
gsub(re, "\\1", str_extract_all(j, re)[[1]])

Celui-ci fonctionne en définissant une sous-expression marquée à l'intérieur de l'expression régulière. Il extrait tout ce qui correspond à l'expression régulière, puis gsub extrait uniquement la partie à l'intérieur de la sous-expression.

21
Dason

Je pense qu'il existe essentiellement trois façons simples d'extraire plusieurs groupes de capture dans R (sans utiliser de substitution); str_match_all, str_extract_all, et regmatches/gregexpr combo.

J'aime le regex de @ kohske, qui cherche derrière une parenthèse ouverte ?<=\\(, attend une parenthèse fermante ?=\\), et saisit tout au milieu (paresseusement) .+?, en d'autres termes (?<=\\().+?(?=\\))

En utilisant le même regex:

str_match_all renvoie la réponse sous la forme matrice.

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" 

str_extract_all renvoie la réponse sous la forme liste.

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

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

regmatches/gregexpr renvoie également la réponse sous la forme liste. Comme il s'agit d'une option de base R, certaines personnes la préfèrent. Notez le 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" 

Espérons que la communauté SO corrigera/modifiera cette réponse si j'ai mal décrit les options les plus populaires.

6
Nettle

L'utilisation de rex peut rendre ce type de tâche un peu plus simple.

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

matches[[1]]$text
#>[1] "wonder" "groan"  "Laugh"
5
Jim