web-dev-qa-db-fra.com

R: comment obtenir grep pour retourner la correspondance, plutôt que la chaîne entière

J'ai ce qui est probablement un grep vraiment stupide en question R. Toutes mes excuses, car cela semble être si facile - il me manque évidemment quelque chose.

J'ai un vecteur de chaînes, appelons-le alice. Une partie de alice est imprimée ci-dessous:

T.8EFF.SP.OT1.D5.VSVOVA#4   
T.8EFF.SP.OT1.D6.LISOVA#1  
T.8EFF.SP.OT1.D6.LISOVA#2   
T.8EFF.SP.OT1.D6.LISOVA#3  
T.8EFF.SP.OT1.D6.VSVOVA#4    
T.8EFF.SP.OT1.D8.VSVOVA#3  
T.8EFF.SP.OT1.D8.VSVOVA#4   
T.8MEM.SP#1                
T.8MEM.SP#3                      
T.8MEM.SP.OT1.D106.VSVOVA#2 
T.8MEM.SP.OT1.D45.LISOVA#1  
T.8MEM.SP.OT1.D45.LISOVA#3

J'aimerais que grep me donne le numéro après le D qui apparaît dans certaines de ces chaînes, conditionnel à la chaîne contenant "LIS" et une chaîne vide ou quelque chose d'autre.

J'espérais que grep me rendrait la valeur d'un groupe de capture plutôt que la chaîne entière. Voici mon expression rationnelle à saveur R:

pattern <- (?<=\\.D)([0-9]+)(?=.LIS)

rien de trop compliqué. Mais afin d'obtenir ce que je recherche, plutôt que d'utiliser simplement grep(pattern, alice, value = TRUE, Perl = TRUE) je fais ce qui suit, ce qui semble mauvais:

reg.out <- regexpr(
    "(?<=\\.D)[0-9]+(?=.LIS)",
    alice,
    Perl=TRUE
)
substr(alice,reg.out,reg.out + attr(reg.out,"match.length")-1)

En le regardant maintenant, cela ne semble pas trop moche, mais la quantité de dégâts qu'il a fallu pour faire fonctionner cette chose tout à fait triviale a été embarrassante. Quelqu'un a des conseils sur la façon de procéder correctement?

Points bonus pour m'avoir dirigé vers une page Web qui explique la différence entre tout ce que j'accède avec $, @ Et attr.

50
Mike Dewar

Vous pouvez faire quelque chose comme ça:

pat <- ".*\\.D([0-9]+)\\.LIS.*"
sub(pat, "\\1", alice)

Si vous voulez uniquement le sous-ensemble de alice où votre modèle correspond, essayez ceci:

pat <- ".*\\.D([0-9]+)\\.LIS.*"
sub(pat, "\\1", alice[grepl(pat, alice)])
37
Ken Williams

Essayez le package stringr:

library(stringr)
str_match(alice, ".*\\.D([0-9]+)\\.LIS.*")[, 2]
53
hadley