2012-06-04 4 views
8

Mam następujące dane:Obcinanie końcu łańcucha w R po znaku, który może być obecny zero lub więcej razy

temp<-c("AIR BAGS:FRONTAL" ,"SERVICE BRAKES HYDRAULIC:ANTILOCK", 
    "PARKING BRAKE:CONVENTIONAL", 
    "SEATS:FRONT ASSEMBLY:POWER ADJUST", 
    "POWER TRAIN:AUTOMATIC TRANSMISSION", 
    "SUSPENSION", 
    "ENGINE AND ENGINE COOLING:ENGINE", 
    "SERVICE BRAKES HYDRAULIC:ANTILOCK", 
    "SUSPENSION:FRONT", 
    "ENGINE AND ENGINE COOLING:ENGINE", 
    "VISIBILITY:WINDSHIELD WIPER/WASHER:LINKAGES") 

Chciałbym utworzyć nowy wektor, który zachowuje tylko tekst przed najpierw ":" w przypadkach, gdy występuje ":", a całe słowo, gdy ":" nie występuje.

Próbowałem użyć:

temp=data.frame(matrix(unlist(str_split(temp,pattern=":",n=2)), 
+      ncol=2, byrow=TRUE)) 

ale to nie działa w przypadkach, gdy nie istnieje „:”

Wiem, że to pytanie jest bardzo podobny do: truncate string from a certain character in R, które kiedyś :

sub("^[^.]*", "", x) 

Ale nie jestem zaznajomiony z wyrażeniami regularnymi i starałem się odwrócić ten przykład, aby zachować tylko początek linii sol.

Odpowiedz

15

Można rozwiązać ten problem z prostym regex:

sub("(.*?):.*", "\\1", x) 
[1] "AIR BAGS"     "SERVICE BRAKES HYDRAULIC" "PARKING BRAKE"    "SEATS"      
[5] "POWER TRAIN"    "SUSPENSION"    "ENGINE AND ENGINE COOLING" "SERVICE BRAKES HYDRAULIC" 
[9] "SUSPENSION"    "ENGINE AND ENGINE COOLING" "VISIBILITY"  

Jak regex działa:

  • "(.*?):.*" Look do wielokrotnego zbioru wszelkich znaków .* ale zmodyfikować go ? aby nie być chciwym. Powinno to nastąpić dwukropkiem a następnie dowolny znak (powtarzane)
  • zastąpić cały łańcuch z bitem znaleźć wewnątrz nawiasów - "\\1"

Bit do zrozumienia jest to, że każdy regex mecz chciwy domyślnie. Modyfikując go tak, aby nie był chciwy, pierwsze dopasowanie wzorca nie może zawierać dwukropka, ponieważ pierwszy znak po nawiasach jest dwukropkiem. Wyrażenie regularne po dwukropku powraca do domyślnego, tj. Zachłanne.

+0

Dzięki za to! i wyjaśnienie regex –

3

to działa (zakładając, że dane jest w postaci wektorowej):

x <- c('foobar','foo:bar','foo1:bar1 foo:bar','foo bar') 
> sapply(str_split(x,":"),'[',1) 
[1] "foobar" "foo"  "foo1" "foo bar" 
+0

(+1) Jest to odpowiedź myślałem od razu. Pod względem szybkości, jak myślisz, co to porównuje do rozwiązań regex? – Dason

+0

@Dason To była też moja myśl, ponieważ tak naprawdę "nie myślę" w regex, ale nie miałem dużych nadziei na szybkość. – joran

1

w tym przypadku

yy<-c("AIR BAGS:FRONTAL", 
"SERVICE BRAKES HYDRAULIC:ANTILOCK", 
"PARKING BRAKE:CONVENTIONAL", 
"SEATS:FRONT ASSEMBLY:POWER ADJUST", 
"POWER TRAIN:AUTOMATIC TRANSMISSION", 
"SUSPENSION", 
"ENGINE AND ENGINE COOLING:ENGINE", 
"SERVICE BRAKES HYDRAULIC:ANTILOCK", 
"SUSPENSION:FRONT", 
"ENGINE AND ENGINE COOLING:ENGINE", 
"VISIBILITY:WINDSHIELD WIPER/WASHER:LINKAGES") 
yy<-gsub("([^:]*).*","\\1",yy) 
yy 

może pracować dla Ciebie

9

Innym podejściem jest patrzeć na pierwszą „:” i zastąpienie go i nic po nim nie ma nic:

yy <- sub(":.*$", "", yy) 

Jeśli nie „:” występuje wtedy nic nie jest podstawiona, a otrzymasz całość oryginalny ciąg. Jeśli istnieje ":", to pierwszy dopasowywany jest wraz ze wszystkim, po czym jest on zastępowany przez nic (""), który usuwa go i pozostawia wszystko do tego pierwszego dwukropka.

3

Przykro mi to dodawać jako odpowiedź.W odpowiedzi na czasy wzięte:

> yy<-rep("foo1:bar1",times=100000) 
> system.time(yy1<-sapply(strsplit(yy,":"),'[',1)) 
    user system elapsed 
    0.26 0.00 0.27 
> 
> system.time(yy2<-sub("(.*?):.*", "\\1", yy)) 
    user system elapsed 
    0.1  0.0  0.1 
> 
> system.time(yy3 <- sub(":.*$", "", yy)) 
    user system elapsed 
    0.08 0.00 0.07 
> 
> system.time(yy4<-gsub("([^:]*).*","\\1",yy)) 
    user system elapsed 
    0.09 0.00 0.09 

regex są w przybliżeniu równoważne strsplit trwa nieco dłużej

+0

Przydatny rozszerzony komentarz. Zauważyłem, że pobudzenie, że regex, który wydawał mi się najprostszy w moim mózgu, @GregSnow był również najszybszy. Pozostałe dwa rozwiązania regex miały charakter informacyjny w celu zilustrowania klas postaci jako sposobu inicjowania "negacji" i wyjaśnienia użycia niezmodyfikowanego "?" tłumić chciwe zachowanie. –