Extraire une sous-chaîne selon un motif

136

Supposons que j'ai une liste de chaînes:

string = c("G1:E001", "G2:E002", "G3:E003")

J'espère maintenant obtenir un vecteur de chaîne qui ne contient que les parties après les deux points ":", c'est à dire substring = c(E001,E002,E003).

Existe-t-il un moyen pratique dans R de faire cela? Utilisation substr?

un petit garçon
la source

Réponses:

239

Voici quelques moyens:

1) sous

sub(".*:", "", string)
## [1] "E001" "E002" "E003"

2) strsplit

sapply(strsplit(string, ":"), "[", 2)
## [1] "E001" "E002" "E003"

3) lire le tableau

read.table(text = string, sep = ":", as.is = TRUE)$V2
## [1] "E001" "E002" "E003"

4) sous-chaîne

Cela suppose que la deuxième partie commence toujours au 4e caractère (ce qui est le cas dans l'exemple de la question):

substring(string, 4)
## [1] "E001" "E002" "E003"

4a) sous-chaîne / regex

Si les deux points n'étaient pas toujours dans une position connue, nous pourrions modifier (4) en le recherchant:

substring(string, regexpr(":", string) + 1)

5) strapplyc

strapplyc renvoie la partie entre parenthèses:

library(gsubfn)
strapplyc(string, ":(.*)", simplify = TRUE)
## [1] "E001" "E002" "E003"

6) read.dcf

Celui-ci ne fonctionne que si les sous-chaînes précédant les deux points sont uniques (ce qu'elles sont dans l'exemple de la question). Il faut aussi que le séparateur soit deux points (ce qui est dans la question). Si un séparateur différent était utilisé, nous pourrions l'utiliser subpour le remplacer d'abord par deux points. Par exemple, si le séparateur était _alorsstring <- sub("_", ":", string)

c(read.dcf(textConnection(string)))
## [1] "E001" "E002" "E003"

7) séparé

7a) En utilisant tidyr::separatenous créons un bloc de données avec deux colonnes, une pour la partie avant les deux points et une pour après, puis extrayons cette dernière.

library(dplyr)
library(tidyr)
library(purrr)

DF <- data.frame(string)
DF %>% 
  separate(string, into = c("pre", "post")) %>% 
  pull("post")
## [1] "E001" "E002" "E003"

7b) Alternativement separatepeut être utilisé pour simplement créer lepost colonne, puis unlistet unnamela trame de données résultant:

library(dplyr)
library(tidyr)

DF %>% 
  separate(string, into = c(NA, "post")) %>% 
  unlist %>%
  unname
## [1] "E001" "E002" "E003"

8) Trimws Nous pouvons utiliser trimwspour couper les caractères des mots sur la gauche, puis l'utiliser à nouveau pour couper les deux points.

trimws(trimws(string, "left", "\\w"), "left", ":")
## [1] "E001" "E002" "E003"

Remarque

L'entrée stringest supposée être:

string <- c("G1:E001", "G2:E002", "G3:E003")
G. Grothendieck
la source
J'avais une variable dans une table fondue qui avait _comme séparateur et créé deux variables distinctes pour le préfixe et le suffixe en fonction de la réponse @Grothendieck: prefix <- sub("_.*", "", variable)et suffix <- sub(".*_", "", variable)
swihart
Ce serait bien de voir un microbenchmarking de cette réponse incroyable!
patL
25

Par exemple en utilisant gsubousub

    gsub('.*:(.*)','\\1',string)
    [1] "E001" "E002" "E003"
étude
la source
pourriez-vous expliquer ce que ces ». * (* et ainsi de suite exactement? J'ai du mal à recréer cela dans un cadre légèrement différent ...
Peter Pan
1
@PeterPan Ceci capture et renvoie le groupe de caractères apparaissant après les deux points. Si les chaînes à associer sont plus compliquées et que vous souhaitez rester en base R, cela fonctionne bien.
Clark Fitzgerald
14

Voici une autre réponse simple

gsub("^.*:","", string)
Ragy Isaac
la source
9

Tard dans la fête, mais pour la postérité, le paquet stringr (qui fait partie de la populaire suite de paquets "tidyverse") fournit désormais des fonctions avec des signatures harmonisées pour la gestion des chaînes:

string <- c("G1:E001", "G2:E002", "G3:E003")
# match string to keep
stringr::str_extract(string = string, pattern = "E[0-9]+")
# [1] "E001" "E002" "E003"

# replace leading string with ""
stringr::str_remove(string = string, pattern = "^.*:")
# [1] "E001" "E002" "E003"
CSJCampbell
la source
2
N'est-ce pas trouver le premier nombre qui commence par un E, plutôt que tout après le colon?
Mark Neal
6

Cela devrait faire:

gsub("[A-Z][1-9]:", "", string)

donne

[1] "E001" "E002" "E003"
user1981275
la source
3

Si vous utilisez data.tablealors tstrsplit()est un choix naturel:

tstrsplit(string, ":")[[2]]
[1] "E001" "E002" "E003"
sindri_baldur
la source
3

Le package unglue fournit une alternative, aucune connaissance des expressions régulières n'est requise pour les cas simples, ici nous ferions:

# install.packages("unglue")
library(unglue)
string = c("G1:E001", "G2:E002", "G3:E003")
unglue_vec(string,"{x}:{y}", var = "y")
#> [1] "E001" "E002" "E003"

Créé le 06/11/2019 par le package reprex (v0.3.0)

Plus d'infos: https://github.com/moodymudskipper/unglue/blob/master/README.md

Moody_Mudskipper
la source