Извлечение чисел из векторов строк

103

У меня есть такая строка:

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

Я хотел бы получить только числовое число из этого вектора. Ожидаемый результат - вектор:

c(20, 1)

Как мне это сделать?

user1471980
источник

Ответы:

87

Как насчет

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

или

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

или

# split by space, get the element in first index
as.numeric(sapply(strsplit(years, " "), "[[", 1))
Арун
источник
1
Зачем это .*нужно? Если вы хотите их с самого начала, почему бы не использовать ^[[:digit:]]+?
sebastian-c
2
.*необходимо, так как вам нужно сопоставить всю строку. Без этого ничего не удаляется. Также обратите внимание, что здесь subможно использовать вместо gsub.
Мэтью Лундберг
14
если число не обязательно должно быть в начале строки, используйте это:gsub(".*?([0-9]+).*", "\\1", years)
TMS
Я хочу получить 27. Я не понимаю, почему, добавляя условия (например, добавляя экранированный «-», результат становится длиннее ... gsub(".*?([0-9]+).*?", "\\1", "Jun. 27–30")Результат: [1] «2730» gsub(".*?([0-9]+)\\-.*?", "\\1", "Jun. 27–30")Результат: [1] «27 июня –30 »
Лайонел Требюшон
66

Я думаю, что подмена - это косвенный путь к решению. Если вы хотите получить все числа, я рекомендую gregexpr:

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

Если у вас есть несколько совпадений в строке, он получит их все. Если вас интересует только первое совпадение, используйте regexprвместо, gregexprи вы можете пропустить unlist.

Себастьян
источник
1
Я этого не ожидал, но это решение на порядок медленнее, чем любое другое.
Мэтью Лундберг
@MatthewLundberg gregexpr, regexprили оба?
sebastian-c
1
gregexpr. Я не пробовал regexprдо сих пор. Огромная разница. Использование regexprставит его между решениями Эндрю и Аруна (второе место по скорости) в сете 1e6. Возможно, также интересно, что использование subв решении Эндрю скорости не улучшает.
Мэтью Лундберг
Это разбивается на основе десятичных знаков. Например, 2.5 становится c ('2', '5')
MBorg
66

Обновление, поскольку extract_numericустарело, мы можем использовать parse_numberfrom readrpackage.

library(readr)
parse_number(years)

Вот еще вариант с extract_numeric

library(tidyr)
extract_numeric(years)
#[1] 20  1
Акрун
источник
2
Прекрасно для этого приложения, но имейте в виду, что parse_numberоно не играет с отрицательными числами. Попробуй parse_number("–27,633")
Крапива
@ Nettle Да, это правильно, и это не сработает, если будет несколько экземпляров,
Акрун
3
Исправлена ​​ошибка синтаксического анализа отрицательных чисел: github.com/tidyverse/readr/issues/308 readr::parse_number("-12,345") # [1] -12345
Russ Hyde
35

Вот альтернатива первому решению Аруна с более простым регулярным выражением, похожим на Perl:

as.numeric(gsub("[^\\d]+", "", years, perl=TRUE))
Андрей
источник
as.numeric(sub("\\D+","",years)). Если были буквы до и или после, тоgsub
Оньямбу 05
21

Или просто:

as.numeric(gsub("\\D", "", years))
# [1] 20  1
989
источник
19

stringrКонвейерное решение:

library(stringr)
years %>% str_match_all("[0-9]+") %>% unlist %>% as.numeric
Джо
источник
Спасибо, Джо, но этот ответ не извлекает отрицательные знаки перед числами в строке.
Miao Cai
16

Вы также можете избавиться от всех букв:

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

Скорее всего, это менее универсально.

Тайлер Ринкер
источник
3
Как ни странно, на моей машине решение Эндрю превосходит это в 5 раз.
Мэтью Лундберг
5

Извлеките числа из любой строки в начальной позиции.

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

Извлекайте числа из любой строки НЕЗАВИСИМО от позиции.

x <- gregexpr("[0-9]+", years)  # Numbers with any number of digits
x2 <- as.numeric(unlist(regmatches(years, x)))
сбанивал
источник
4

Мы также можем использовать str_extractотstringr

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

Если в строке есть несколько чисел, и мы хотим извлечь их все, мы можем использовать str_extract_allwhich, в отличие от str_extractвозвращающих все 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

После сообщения Габора Гротендика в списке рассылки 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]])
Хуанбретти
источник