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?

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))

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.


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

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))

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

19

Una stringrsolución canalizada:

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

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.


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)))

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"

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]])

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.