2013-04-09 12 views
36

Mam listę urodzin, które wyglądają mniej więcej tak:Korzystanie gsub wyodrębnić ciąg znaków przed białym przestrzeni R

dob <- c("9/9/43 12:00 AM/PM", "9/17/88 12:00 AM/PM", "11/21/48 12:00 AM/PM") 

Chcę po prostu chwycić datę kalendarza z tej zmiennej (czyli rzucić wszystko po pierwsze pojawienie się białej przestrzeni).

Oto, co starałem dotąd:

dob.abridged <- substring(dob,1,8) 
dob 
[1] "9/9/43 1" "9/17/88 " "11/21/48" 
dob.abridged <- gsub(" $","", dob.abridged, perl=T) 
> dob.abridged 
[1] "9/9/43 1" "9/17/88" "11/21/48" 

Więc mój kod działa dla dat kalendarzowych od długości 6 lub 7, ale nie długość 8. Wszelkie wskazówki na temat bardziej efektywnego regex korzystać z gsub które mogą obsługiwać daty kalendarzowe o długości 6, 7 lub 8?

Dziękuję.

Odpowiedz

85

Nie potrzeba substring, wystarczy użyć gsub:

gsub(" .*$", "", dob) 
# [1] "9/9/43" "9/17/88" "11/21/48" 

przestrzeń (), a następnie dowolny znak (.) dowolną ilość razy (*) aż do końca łańcucha ($). Aby dowiedzieć się wyrażeń regularnych, zobacz ?regex.

+2

Jedyną radą, którą mogę tutaj podzielić, jest to, że 'sub' jest wystarczające, ponieważ istnieje tylko jedna pozycja końca łańcucha. –

13

Często używam tego rodzaju problemów z strsplit, ale spodobało mi się, jak prosta była odpowiedź Romaina. Pomyślałem, że byłoby ciekawie porównać rozwiązanie Romain jest do strsplit odpowiedź:

Oto strsplit rozwiązanie:

sapply(strsplit(dob, "\\s+"), "[", 1) 

Korzystanie pakiet microbenchmark i dob <- rep(dob, 1000) z oryginalnych danych:

Unit: milliseconds 
            expr  min  lq median 
        gsub(" .*$", "", dob) 4.228843 4.247969 4.258232 
sapply(strsplit(dob, "\\\\s+"), "[", 1) 14.438241 14.558832 14.634638 
     uq  max neval 
    4.268029 5.081608 1000 
14.756628 53.344984 1000 

The Wyraźnym zwycięzcą na maszynie Win 7 jest regex z Romaina o numerze gsub. Dzięki za odpowiedź i wyjaśnienie Romain.

1

Biblioteka stringr zawiera funkcję dostosowaną do tego problemu.

library(stringr) 
word(dob,1) 
# [1] "9/9/43" "9/17/88" "11/21/48"