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.