Mengekstrak angka dari vektor string

103

Saya memiliki string seperti ini:

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

Saya hanya ingin grep nomor numerik dari vektor ini. Output yang diharapkan adalah vektor:

c(20, 1)

Bagaimana cara saya melakukan ini?

pengguna1471980
sumber

Jawaban:

87

Bagaimana tentang

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

atau

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

atau

# split by space, get the element in first index
as.numeric(sapply(strsplit(years, " "), "[[", 1))
Arun
sumber
1
Mengapa .*perlu? Jika Anda menginginkannya di awal, mengapa tidak digunakan ^[[:digit:]]+?
sebastian-c
2
.*diperlukan karena Anda harus mencocokkan seluruh string. Tanpa itu, tidak ada yang dihapus. Juga, catatan yang subdapat digunakan di sini sebagai pengganti gsub.
Matthew Lundberg
14
jika nomor tersebut tidak harus di awal string, gunakan ini:gsub(".*?([0-9]+).*", "\\1", years)
TMS
Saya ingin mendapatkan 27. Saya tidak mengerti mengapa, dengan menambahkan kondisi (seperti menambahkan "-" yang lolos, hasilnya menjadi lebih panjang ... gsub(".*?([0-9]+).*?", "\\1", "Jun. 27–30")Hasil: [1] "2730" gsub(".*?([0-9]+)\\-.*?", "\\1", "Jun. 27–30")Hasil: [1] "27 Jun. –30 "
Lionel Trebuchon
66

Saya pikir substitusi adalah cara tidak langsung untuk mencapai solusi. Jika Anda ingin mengambil semua nomor, saya sarankan gregexpr:

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

Jika Anda memiliki beberapa kecocokan dalam satu string, ini akan mendapatkan semuanya. Jika Anda hanya tertarik pada pertandingan pertama, gunakan regexprsebagai pengganti gregexprdan Anda dapat melewati unlist.

sebastian-c
sumber
1
Saya tidak mengharapkannya, tetapi solusi ini lebih lambat daripada yang lain, berdasarkan urutan besarnya.
Matthew Lundberg
@ MatthewLundberg gregexpr, regexpratau keduanya?
sebastian-c
1
gregexpr. Saya belum mencoba regexprsampai sekarang. Perbedaan BESAR. Menggunakan regexprmenempatkannya di antara solusi Andrew dan Arun (tercepat kedua) pada set 1e6. Mungkin juga menarik, menggunakan subsolusi Andrew tidak meningkatkan kecepatan.
Matthew Lundberg
Pembagian ini berdasarkan titik desimal. Misalnya 2.5 menjadi c ('2', '5')
MBorg
66

Perbarui Karena extract_numerictidak digunakan lagi, kita dapat menggunakan parse_numberdari readrpaket.

library(readr)
parse_number(years)

Berikut adalah opsi lain dengan extract_numeric

library(tidyr)
extract_numeric(years)
#[1] 20  1
akrun
sumber
2
Baik untuk aplikasi ini tetapi perlu diingat parse_numberjangan bermain-main dengan angka negatif. Coba parse_number("–27,633")
Nettle
@Nettle Ya, itu benar dan itu tidak akan berfungsi jika ada beberapa contoh juga
akrun
3
Bug penguraian angka negatif telah diperbaiki: github.com/tidyverse/readr/issues/308 readr::parse_number("-12,345") # [1] -12345
Russ Hyde
35

Berikut alternatif solusi pertama Arun, dengan ekspresi reguler mirip Perl yang lebih sederhana:

as.numeric(gsub("[^\\d]+", "", years, perl=TRUE))
Andrew
sumber
as.numeric(sub("\\D+","",years)). Jika ada surat sebelum dan | atau sesudahnya, makagsub
Onyambu
21

Atau sederhananya:

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

Sebuah stringrsolusi pipelined:

library(stringr)
years %>% str_match_all("[0-9]+") %>% unlist %>% as.numeric
Joe
sumber
Terima kasih Joe, tetapi jawaban ini tidak mengekstrak tanda negatif sebelum angka dalam string.
Miao Cai
16

Anda juga bisa menyingkirkan semua huruf:

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

Mungkin ini kurang bisa digeneralisasikan.

Tyler Rinker
sumber
3
Anehnya, solusi Andrew mengalahkan ini dengan faktor 5 pada mesin saya.
Matthew Lundberg
5

Ekstrak angka dari string apa pun di posisi awal.

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

Ekstrak angka dari sembarang string INDEPENDEN posisi.

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

Kami juga dapat menggunakan str_extractdaristringr

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

Jika ada beberapa angka dalam string dan kami ingin mengekstrak semuanya, kami dapat menggunakan str_extract_allyang tidak seperti str_extractmengembalikan semua 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
sumber
2

Setelah posting dari Gabor Grothendieck posting di milis 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
sumber