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?

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))

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.


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

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))

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

19

Eine stringrPipeline-Lösung:

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

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.


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)))

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"

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]])

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.