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


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.