Extraer números de vectores de cadenas

101

Tengo una cadena como esta:

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

Me gustaría grep solo el número numérico de este vector. La salida esperada es un vector:

c(20, 1)

¿Cómo voy a hacer esto?

usuario1471980
fuente

Respuestas:

83

Qué tal si

# 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))
Arun
fuente
1
¿Por qué es .*necesario? Si los quiere al principio, ¿por qué no usarlos ^[[:digit:]]+?
sebastian-c
2
.*es necesario ya que debe hacer coincidir toda la cadena. Sin eso, no se quita nada. Además, tenga en cuenta que subse puede utilizar aquí en lugar de gsub.
Matthew Lundberg
12
si el número no tiene que estar al principio de la cadena, use esto:gsub(".*?([0-9]+).*", "\\1", years)
TMS
Quiero obtener 27. No entiendo por qué, al agregar condiciones (como agregar un "-" de escape, el resultado se alarga ... gsub(".*?([0-9]+).*?", "\\1", "Jun. 27–30")Resultado: [1] "2730" gsub(".*?([0-9]+)\\-.*?", "\\1", "Jun. 27–30")Resultado: [1] "27 de junio –30 "
Lionel Trebuchon
65

Creo que la sustitución es una forma indirecta de llegar a la solución. Si desea recuperar todos los números, le recomiendo gregexpr:

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

Si tiene varias coincidencias en una cadena, esto las obtendrá todas. Si solo está interesado en la primera coincidencia, use en regexprlugar de gregexpry puede omitir el unlist.

sebastian-c
fuente
1
No lo esperaba, pero esta solución es más lenta que cualquiera de las otras, en un orden de magnitud.
Matthew Lundberg
@MatthewLundberg ¿el gregexpr, regexpro ambos?
sebastian-c
1
gregexpr. No lo había intentado regexprhasta ahora. Gran diferencia. Usar lo regexprcoloca entre las soluciones de Andrew y Arun (el segundo más rápido) en un set de 1e6. Quizás también sea interesante, usar suben la solución de Andrew no mejora la velocidad.
Matthew Lundberg
Esto se divide en base a puntos decimales. Por ejemplo, 2.5 se convierte en c ('2', '5')
MBorg
65

Actualización Dado que extract_numericestá en desuso, podemos usar parse_numberfrom readrpackage.

library(readr)
parse_number(years)

Aquí hay otra opción con extract_numeric

library(tidyr)
extract_numeric(years)
#[1] 20  1
Akrun
fuente
2
Está bien para esta aplicación pero ten en cuenta parse_numberque no se juega con números negativos. Try parse_number("–27,633")
Ortiga
@Nettle Sí, eso es correcto y no funcionará si también hay varias instancias
akrun
3
El error de análisis de números negativos se ha corregido: github.com/tidyverse/readr/issues/308 readr::parse_number("-12,345") # [1] -12345
Russ Hyde
35

Aquí hay una alternativa a la primera solución de Arun, con una expresión regular similar a Perl más simple:

as.numeric(gsub("[^\\d]+", "", years, perl=TRUE))
Andrés
fuente
as.numeric(sub("\\D+","",years)). Si hubo letras antes y | o después, entoncesgsub
Onyambu
21

O simplemente:

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

Una stringrsolución canalizada:

library(stringr)
years %>% str_match_all("[0-9]+") %>% unlist %>% as.numeric
Joe
fuente
Gracias Joe, pero esta respuesta no extrae los signos negativos antes de los números en la cadena.
Miao Cai
16

También podrías deshacerte de todas las letras:

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

Sin embargo, es probable que esto sea menos generalizable.

Tyler Rinker
fuente
3
Curiosamente, la solución de Andrew supera esto por un factor de 5 en mi máquina.
Matthew Lundberg
5

Extrae números de cualquier cadena en la posición inicial.

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

Extrae números de cualquier cadena INDEPENDIENTE de la posición.

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

También podemos utilizar str_extractdesdestringr

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

Si hay varios números en la cadena y queremos extraerlos todos, podemos usar str_extract_allque, a diferencia de, str_extractdevuelve todos los 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"
Ronak Shah
fuente
2

Después de la publicación de Gabor Grothendieck en la lista de correo de r-help

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

library(gsubfn)
pat <- "[-+.e0-9]*\\d"
sapply(years, function(x) strapply(x, pat, as.numeric)[[1]])
juanbretti
fuente