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.