Estrazione di numeri da vettori di stringhe


101

Ho una stringa come questa:

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

Vorrei grep solo il numero numerico da questo vettore. L'output previsto è un vettore:

c(20, 1)

Come procedo a fare questo?

Risposte:


83

Che ne dite di

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

o

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

o

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

1
Perché è .*necessario? Se li vuoi all'inizio, perché non usarli ^[[:digit:]]+?
sebastian-c

2
.*è necessario in quanto è necessario abbinare l'intera stringa. Senza quello, nulla viene rimosso. Inoltre, nota che subpuò essere utilizzato qui invece di gsub.
Matthew Lundberg,

12
se il numero non deve essere all'inizio della stringa, utilizzare questo:gsub(".*?([0-9]+).*", "\\1", years)
TMS

Voglio ottenere 27. Non capisco perché, aggiungendo condizioni (come l'aggiunta di un "-" con escape, il risultato si allunga ... gsub(".*?([0-9]+).*?", "\\1", "Jun. 27–30")Risultato: [1] "2730" gsub(".*?([0-9]+)\\-.*?", "\\1", "Jun. 27–30")Risultato: [1] "Jun. 27 –30 "
Lionel Trebuchon

65

Penso che la sostituzione sia un modo indiretto per arrivare alla soluzione. Se vuoi recuperare tutti i numeri, ti consiglio gregexpr:

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

Se hai più corrispondenze in una stringa, verranno ottenute tutte. Se sei interessato solo alla prima corrispondenza, usa regexprinvece di gregexpre puoi saltare il unlist.


1
Non me l'aspettavo, ma questa soluzione è più lenta di tutte le altre, di un ordine di grandezza.
Matthew Lundberg,

@ MatthewLundberg il gregexpr, regexpro entrambi?
sebastian-c

1
gregexpr. Non ci avevo provato regexprfino ad ora. Differenza enorme. L'utilizzo lo regexprcolloca tra le soluzioni di Andrew e Arun (la seconda più veloce) su un set 1e6. Forse anche interessante, l'utilizzo subnella soluzione di Andrew non migliora la velocità.
Matthew Lundberg,

Questo divide in base ai punti decimali. Ad esempio 2.5 diventa c ('2', '5')
MBorg

65

Aggiorna Poiché extract_numericè deprecato, possiamo usare parse_numberfrom readrpackage.

library(readr)
parse_number(years)

Ecco un'altra opzione con extract_numeric

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

2
Va bene per questa applicazione ma tieni presente che parse_numbernon si gioca con numeri negativi. Prova parse_number("–27,633")
Ortica

@Nettle Sì, è vero e non funzionerà anche se ci sono più istanze
akrun

3
Il bug di analisi del numero negativo è stato corretto: github.com/tidyverse/readr/issues/308 readr::parse_number("-12,345") # [1] -12345
Russ Hyde

35

Ecco un'alternativa alla prima soluzione di Arun, con un'espressione regolare più semplice simile a Perl:

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

as.numeric(sub("\\D+","",years)). Se c'erano lettere prima e | o dopo, alloragsub
Onyambu

21

O semplicemente:

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

19

Una stringrsoluzione pipeline:

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

Grazie Joe, ma questa risposta non estrae i segni negativi prima dei numeri nella stringa.
Miao Cai

16

Potresti sbarazzarti anche di tutte le lettere:

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

Probabilmente questo è meno generalizzabile.


3
Stranamente, la soluzione di Andrew batte questo di un fattore 5 sulla mia macchina.
Matthew Lundberg

5

Estrae i numeri da qualsiasi stringa nella posizione iniziale.

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

Estrai numeri da qualsiasi stringa INDIPENDENTE dalla posizione.

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

4

Possiamo anche usare str_extractdastringr

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

Se ci sono più numeri nella stringa e vogliamo estrarli tutti, possiamo usare str_extract_allche a differenza di str_extractrestituisce tutti i 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"


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.