Extração de números de vetores de strings

101

Eu tenho uma string assim:

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

Eu gostaria de usar o grep apenas para o número numérico desse vetor. A saída esperada é um vetor:

c(20, 1)

Como faço para fazer isso?

user1471980
fonte

Respostas:

83

E se

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

ou

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

ou

# split by space, get the element in first index
as.numeric(sapply(strsplit(years, " "), "[[", 1))
Uma corrida
fonte
1
Por que é .*necessário? Se você quer no início, por que não usar ^[[:digit:]]+?
sebastian-c
2
.*é necessário, pois você precisa corresponder a toda a string. Sem isso, nada é removido. Além disso, observe que subpode ser usado aqui em vez de gsub.
Matthew Lundberg
12
se o número não precisa estar no início da string, use este:gsub(".*?([0-9]+).*", "\\1", years)
TMS
Quero obter 27. Não entendo por que, ao adicionar condições (como adicionar um "-" com escape, o resultado fica mais longo ... gsub(".*?([0-9]+).*?", "\\1", "Jun. 27–30")Resultado: [1] "2730" gsub(".*?([0-9]+)\\-.*?", "\\1", "Jun. 27–30")Resultado: [1] "27 de junho –30 "
Lionel Trebuchon
65

Acho que a substituição é uma forma indireta de se chegar à solução. Se você deseja recuperar todos os números, recomendo gregexpr:

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

Se você tiver várias correspondências em uma string, todas elas serão obtidas. Se você estiver interessado apenas na primeira correspondência, use em regexprvez de gregexpre poderá pular o unlist.

sebastian-c
fonte
1
Eu não esperava, mas essa solução é mais lenta do que qualquer uma das outras, em uma ordem de magnitude.
Matthew Lundberg
@MatthewLundberg the gregexpr, regexprou ambos?
sebastian-c
1
gregexpr. Eu não tinha tentado regexpraté agora. Enorme diferença. Usar o regexprcoloca entre as soluções de Andrew e Arun (o segundo mais rápido) em um conjunto 1e6. Talvez também seja interessante, usar suba solução de Andrew não melhora a velocidade.
Matthew Lundberg
Isso se divide com base em pontos decimais. Por exemplo, 2,5 torna-se c ('2', '5')
MBorg
65

Atualizar Como extract_numericestá obsoleto, podemos usar parse_numberdo readrpacote.

library(readr)
parse_number(years)

Aqui está outra opção com extract_numeric

library(tidyr)
extract_numeric(years)
#[1] 20  1
Akrun
fonte
2
Bom para esta aplicação, mas tenha em mente parse_numberque não brinca com números negativos. Teste parse_number("–27,633")
Nettle
@Nettle Sim, está certo e não funcionará se houver várias instâncias também
akrun
3
O bug de análise de número negativo foi corrigido: github.com/tidyverse/readr/issues/308 readr::parse_number("-12,345") # [1] -12345
Russ Hyde
35

Aqui está uma alternativa para a primeira solução de Arun, com uma expressão regular semelhante ao Perl mais simples:

as.numeric(gsub("[^\\d]+", "", years, perl=TRUE))
Andrew
fonte
as.numeric(sub("\\D+","",years)). Se houvesse cartas antes e | ou depois, entãogsub
Onyambu
21

Ou simplesmente:

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

Uma stringrsolução em pipeline:

library(stringr)
years %>% str_match_all("[0-9]+") %>% unlist %>% as.numeric
Joe
fonte
Obrigado Joe, mas esta resposta não extrai os sinais negativos antes dos números na string.
Miao Cai
16

Você também pode se livrar de todas as letras:

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

Provavelmente, isso é menos generalizável.

Tyler Rinker
fonte
3
Estranhamente, a solução de Andrew supera isso por um fator de 5 na minha máquina.
Matthew Lundberg
5

Extraia números de qualquer string na posição inicial.

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

Extraia números de qualquer string INDEPENDENTE de posição.

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

Também podemos usar str_extractdestringr

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

Se houver vários números na string e quisermos extrair todos eles, podemos usar o str_extract_allqual, ao contrário, str_extractretorna todos os 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
fonte
2

Após a postagem de Gabor Grothendieck, poste na lista de discussão 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
fonte