2012-06-04 4 views
8

ho i seguenti dati:Troncare la fine di una stringa in R dopo un carattere che può essere presente zero o più volte

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

Vorrei creare un nuovo vettore che conserva solo il testo prima della prima ":" nei casi in cui è presente un ":" e l'intera parola quando ":" non è presente.

ho cercato di usare:

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

ma non funziona nei casi in cui non v'è alcuna ":"

So che questa domanda è molto simile a: truncate string from a certain character in R, che ha usato :

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

Ma io non sono molto familiare con le espressioni regolari e hanno lottato per invertire tale esempio di mantenere solo l'inizio del strIn g.

risposta

15

È possibile risolvere questo con un semplice 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"  

Come funziona la regex:

  • "(.*?):.*" Cercare una serie ripetuta di caratteri .* ma modificarlo con ? di non essere avidi. Questo dovrebbe essere seguito da due punti e quindi qualsiasi carattere (ripetuta)
  • Sostituto l'intera stringa con il bit trovato all'interno delle parentesi - "\\1"

Il bit da capire è che ogni partita regex è avido di default. Modificandolo come non-goloso, la prima corrispondenza del modello non può includere i due punti, poiché il primo carattere dopo le parentesi è un due punti. L'espressione regolare dopo il colon è tornata al valore predefinito, cioè avido.

+0

Grazie per questo! e la spiegazione della regex –

3

fa questo lavoro (supponendo che i dati sono in un vettore di carattere):

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

(+1) Questa è la risposta ho pensato subito. In termini di velocità, come pensi che questo sia paragonabile alle soluzioni regex? – Dason

+0

@Dason E 'stato anche il mio pensiero perché non ho ancora "pensato" nella regex, ma non avevo grandi speranze di velocità. – joran

1

in questo caso

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 

può funzionare per voi

9

Un altro approccio è quello di cercare la prima ":" e sostituirlo e tutto ciò dopo che con niente:

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

Se no ":" si ritrova allora niente viene sostituito e si ottiene tutto il stringa originale. Se c'è un ":" allora il primo viene abbinato insieme a tutto ciò che segue, questo viene quindi sostituito con niente ("") che lo elimina e lascia tutto fino ai primi due punti.

3

scusa per aggiungere questo come risposta.In risposta a volte presi:

> 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 

La regex sono meno equivalente alla strsplit impiega più tempo

+0

Commento esteso utile. Ho trovato incoraggiante che la regex che sembrava la più semplice per il mio cervello, @GregSnow è stata anche la più veloce. Le altre due soluzioni regex erano informative per la loro illustrazione delle classi di caratteri come un modo per iniziare la "negazione" e la spiegazione dell'uso non modificato "?" per sopprimere il comportamento avido. –

Problemi correlati