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"
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.
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.
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.
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"