Zahlen aus Vektoren von Strings extrahieren

100

Ich habe eine Zeichenfolge wie diese:

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

Ich möchte nur die numerische Zahl aus diesem Vektor erfassen. Die erwartete Ausgabe ist ein Vektor:

c(20, 1)

Wie mache ich das?

user1471980
quelle

Antworten:

82

Wie wäre es mit

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

oder

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

oder

# split by space, get the element in first index
as.numeric(sapply(strsplit(years, " "), "[[", 1))
Arun
quelle
1
Warum ist das .*notwendig? Wenn Sie sie am Anfang haben möchten, warum nicht verwenden ^[[:digit:]]+?
Sebastian-c
2
.*ist erforderlich, da Sie die gesamte Zeichenfolge abgleichen müssen. Ohne das wird nichts entfernt. Beachten Sie auch, dass subhier anstelle von verwendet werden kann gsub.
Matthew Lundberg
12
Wenn die Nummer nicht am Anfang der Zeichenfolge stehen muss, verwenden Sie Folgendes:gsub(".*?([0-9]+).*", "\\1", years)
TMS
Ich möchte 27 erhalten. Ich verstehe nicht, warum durch Hinzufügen von Bedingungen (z. B. Hinzufügen eines maskierten "-") das Ergebnis länger wird ... gsub(".*?([0-9]+).*?", "\\1", "Jun. 27–30")Ergebnis: [1] "2730" gsub(".*?([0-9]+)\\-.*?", "\\1", "Jun. 27–30")Ergebnis: [1] "27. Juni –30 "
Lionel Trebuchon
64

Ich denke, dass Substitution ein indirekter Weg ist, um zur Lösung zu gelangen. Wenn Sie alle Nummern abrufen möchten, empfehle ich gregexpr:

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

Wenn Sie mehrere Übereinstimmungen in einer Zeichenfolge haben, werden alle diese erhalten. Wenn Sie nur am ersten Spiel interessiert sind, verwenden Sie regexprstattdessen gregexprund Sie können das überspringen unlist.

sebastian-c
quelle
1
Ich habe es nicht erwartet, aber diese Lösung ist um eine Größenordnung langsamer als jede andere.
Matthew Lundberg
@MatthewLundberg das gregexpr, regexproder beides?
Sebastian-c
1
gregexpr. Ich hatte es regexprbis jetzt nicht versucht . RIESIGER Unterschied. Mit regexprsetzt es zwischen Andrews und Aruns Lösungen (zweitschnellste) auf einem 1e6-Set. Vielleicht auch interessant, die Verwendung subin Andrews Lösung verbessert die Geschwindigkeit nicht.
Matthew Lundberg
Dies wird basierend auf Dezimalstellen aufgeteilt. Zum Beispiel wird 2.5 zu c ('2', '5')
MBorg
64

Update Da extract_numericveraltet ist, können wir parse_numberaus readrPaket verwenden.

library(readr)
parse_number(years)

Hier ist eine weitere Option mit extract_numeric

library(tidyr)
extract_numeric(years)
#[1] 20  1
akrun
quelle
2
Gut für diese Anwendung, aber denken Sie daran, parse_numberspielt nicht mit negativen Zahlen. Versuchen Sie parse_number("–27,633")
Brennnessel
@Nettle Ja, das ist richtig und es wird nicht funktionieren, wenn es auch mehrere Instanzen gibt
akrun
3
Der Fehler beim Parsen negativer Zahlen wurde behoben: github.com/tidyverse/readr/issues/308 readr::parse_number("-12,345") # [1] -12345
Russ Hyde
35

Hier ist eine Alternative zu Aruns erster Lösung mit einem einfacheren Perl-ähnlichen regulären Ausdruck:

as.numeric(gsub("[^\\d]+", "", years, perl=TRUE))
Andrew
quelle
as.numeric(sub("\\D+","",years)). Wenn es vorher und nachher Briefe gab, danngsub
Onyambu
21

Oder einfach:

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

Eine stringrPipeline-Lösung:

library(stringr)
years %>% str_match_all("[0-9]+") %>% unlist %>% as.numeric
Joe
quelle
Danke Joe, aber diese Antwort extrahiert nicht die negativen Vorzeichen vor den Zahlen in der Zeichenfolge.
Miao Cai
16

Sie könnten auch alle Buchstaben loswerden:

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

Wahrscheinlich ist dies jedoch weniger verallgemeinerbar.

Tyler Rinker
quelle
3
Seltsamerweise übertrifft Andrews Lösung dies auf meinem Computer um den Faktor 5.
Matthew Lundberg
5

Extrahieren Sie Zahlen aus einer beliebigen Zeichenfolge an der Anfangsposition.

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

Extrahieren Sie Zahlen aus einer beliebigen Zeichenfolge, die von der Position UNABHÄNGIG ist.

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

Wir können auch str_extractvon verwendenstringr

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

Wenn die Zeichenfolge mehrere Zahlen enthält und wir alle extrahieren möchten, können wir verwenden, str_extract_alldie im Gegensatz zu str_extractallen Zahlen alle Macthes zurückgeben.

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
quelle
2

Nach dem Beitrag von Gabor Grothendieck auf der R-Hilfe-Mailingliste

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
quelle