Вилучення чисел з векторів рядків


101

У мене такий рядок:

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

Я хотів би взяти лише числове число з цього вектора. Очікуваний результат - вектор:

c(20, 1)

Як я можу це зробити?

Відповіді:


83

Як щодо

# 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.
Метью Лундберг,

12
якщо число не повинно бути на початку рядка, використовуйте це: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 "
Ліонель

65

Я думаю, що заміна - це непрямий спосіб дійти до рішення. Якщо ви хочете отримати всі номери, я рекомендую gregexpr:

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

Якщо у вас є кілька збігів у рядку, це отримає всі. Якщо вас цікавить лише перший збіг, використовуйте regexprзамість gregexprі можна пропустити unlist.


1
Я не очікував цього, але це рішення повільніше, ніж будь-яке інше, на порядок.
Matthew Lundberg

@MatthewLundberg the gregexpr, regexprабо обидва?
sebastian-c

1
gregexpr. Я не пробував regexprдо цього часу. ВЕЛИЧЕЗНА різниця. Використання regexprставить його між рішеннями Ендрю та Аруна (друге за швидкістю) на наборі 1e6. Можливо, також цікаво, якщо використання subрішення Ендрю не покращує швидкість.
Matthew Lundberg

Це розбивається на основі десяткових крапок. Наприклад 2.5 стає c ('2', '5')
MBorg

65

Оновлення Оскільки extract_numericзасуджується, ми можемо використовувати parse_numberз readrпакета.

library(readr)
parse_number(years)

Ось ще один варіант з extract_numeric

library(tidyr)
extract_numeric(years)
#[1] 20  1

2
Чудово для цієї програми, але майте на увазі, parse_numberщо не грає з від’ємними числами. Спробуйте parse_number("–27,633")
Кропива

@Nettle Так, це правильно, і це не спрацює, якщо також є кілька екземплярів
akrun

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
Онямбу


19

stringrКонвеєрне рішення:

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

Дякую Джо, але ця відповідь не витягує негативні знаки перед цифрами у рядку.
Мяо Цай

16

Ви також можете позбутися всіх літер:

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

Ймовірно, це менш узагальнююче.


3
Дивно, але рішення Ендрю перевершує це в 5 разів на моїй машині.
Matthew Lundberg

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_allщо на відміну від str_extractповертає всі макти.

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"


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.