Extraction de nombres à partir de vecteurs de chaînes


101

J'ai une chaîne comme celle-ci:

years<-c("20 years old", "1 years old")

Je voudrais grep uniquement le nombre numérique de ce vecteur. La sortie attendue est un vecteur:

c(20, 1)

Comment dois-je procéder?

Réponses:


83

Que diriez-vous

# pattern is by finding a set of numbers in the start and capturing them
as.numeric(gsub("([0-9]+).*$", "\\1", years))

ou

# pattern is to just remove _years_old
as.numeric(gsub(" years old", "", years))

ou

# split by space, get the element in first index
as.numeric(sapply(strsplit(years, " "), "[[", 1))

1
Pourquoi le .*nécessaire? Si vous les voulez au départ, pourquoi ne pas les utiliser ^[[:digit:]]+?
sebastian-c

2
.*est nécessaire car vous devez faire correspondre la chaîne entière. Sans cela, rien n'est supprimé. Notez également que cela subpeut être utilisé ici à la place de gsub.
Matthew Lundberg

12
si le nombre ne doit pas nécessairement être au début de la chaîne, utilisez ceci:gsub(".*?([0-9]+).*", "\\1", years)
TMS

Je veux obtenir 27. Je ne comprends pas pourquoi, en ajoutant des conditions (comme l'ajout d'un "-" échappé, le résultat s'allonge ... gsub(".*?([0-9]+).*?", "\\1", "Jun. 27–30")Résultat: [1] "2730" gsub(".*?([0-9]+)\\-.*?", "\\1", "Jun. 27–30")Résultat: [1] "27 juin –30 "
Lionel Trebuchon

65

Je pense que la substitution est un moyen indirect d'arriver à la solution. Si vous souhaitez récupérer tous les numéros, je vous recommande gregexpr:

matches <- regmatches(years, gregexpr("[[:digit:]]+", years))
as.numeric(unlist(matches))

Si vous avez plusieurs correspondances dans une chaîne, cela les obtiendra toutes. Si vous n'êtes intéressé que par le premier match, utilisez à la regexprplace de gregexpret vous pouvez ignorer le unlist.


1
Je ne m'y attendais pas, mais cette solution est plus lente que toutes les autres, d'un ordre de grandeur.
Matthew Lundberg

@MatthewLundberg le gregexpr, regexprou les deux?
sebastian-c

1
gregexpr. Je n'avais pas essayé regexprjusqu'à maintenant. Énorme différence. L'utilisation le regexprmet entre les solutions d'Andrew et d'Arun (deuxième plus rapide) sur un set 1e6. Peut-être aussi intéressant, l'utilisation subdans la solution d'Andrew n'améliore pas la vitesse.
Matthew Lundberg

Cela divise en fonction des points décimaux. Par exemple 2,5 devient c ('2', '5')
MBorg

65

Update Depuis extract_numericest obsolète, nous pouvons utiliser parse_numberfrom readrpackage.

library(readr)
parse_number(years)

Voici une autre option avec extract_numeric

library(tidyr)
extract_numeric(years)
#[1] 20  1

2
Bien pour cette application, mais gardez à l'esprit parse_numberque ne joue pas avec des nombres négatifs. Essayer parse_number("–27,633")
Nettle

@Nettle Oui, c'est vrai et cela ne fonctionnera pas s'il y a plusieurs instances également
akrun

3
Le bogue d'analyse des nombres négatifs a été corrigé: github.com/tidyverse/readr/issues/308 readr::parse_number("-12,345") # [1] -12345
Russ Hyde

35

Voici une alternative à la première solution d'Arun, avec une expression régulière plus simple de type Perl:

as.numeric(gsub("[^\\d]+", "", years, perl=TRUE))

as.numeric(sub("\\D+","",years)). S'il y avait des lettres avant et | ou après, alorsgsub
Onyambu

21

Ou simplement:

as.numeric(gsub("\\D", "", years))
# [1] 20  1

19

Une stringrsolution en pipeline:

library(stringr)
years %>% str_match_all("[0-9]+") %>% unlist %>% as.numeric

Merci Joe, mais cette réponse n'extrait pas les signes négatifs avant les nombres dans la chaîne.
Miao Cai

16

Vous pouvez également vous débarrasser de toutes les lettres:

as.numeric(gsub("[[:alpha:]]", "", years))

Cela est probablement moins généralisable.


3
Curieusement, la solution d'Andrew bat cela par un facteur de 5 sur ma machine.
Matthew Lundberg

5

Extrayez les nombres de n'importe quelle chaîne à la position de début.

x <- gregexpr("^[0-9]+", years)  # Numbers with any number of digits
x2 <- as.numeric(unlist(regmatches(years, x)))

Extraire les nombres de n'importe quelle chaîne INDÉPENDANTE de position.

x <- gregexpr("[0-9]+", years)  # Numbers with any number of digits
x2 <- as.numeric(unlist(regmatches(years, x)))

4

Nous pouvons également utiliser str_extractdestringr

years<-c("20 years old", "1 years old")
as.integer(stringr::str_extract(years, "\\d+"))
#[1] 20  1

S'il y a plusieurs nombres dans la chaîne et que nous voulons tous les extraire, nous pouvons utiliser str_extract_allqui, contrairement à, str_extractrenvoie tous les macthes.

years<-c("20 years old and 21", "1 years old")
stringr::str_extract(years, "\\d+")
#[1] "20"  "1"

stringr::str_extract_all(years, "\\d+")

#[[1]]
#[1] "20" "21"

#[[2]]
#[1] "1"


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.