2012-06-04 855 views
8

tengo los siguientes datos:truncar el final de una cadena en I después de un personaje que puede estar presente cero o más veces

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

me gustaría crear un nuevo vector que retiene sólo el texto antes de la primero ":" en los casos donde ":" está presente, y la palabra completa cuando ":" no está presente.

me han tratado de usar:

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

pero no funciona en los casos en que no hay ":"

Sé que esta pregunta es muy similar a: truncate string from a certain character in R, que utiliza :

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

Pero no estoy muy familiarizado con las expresiones regulares y he tenido problemas para invertir ese ejemplo para retener solo el comienzo de la línea gramo.

Respuesta

15

Puede resolver esto con un simple 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"  

cómo funciona la expresión regular:

  • "(.*?):.*" Look para un conjunto repetido de cualquier carácter .* pero modificarlo con ? a no ser codicioso. Esto debe ser seguido de dos puntos y luego cualquier carácter (repetido)
  • Sustituto de toda la cadena con el bit que se encuentra dentro de los paréntesis - "\\1"

El bit que entender es que cualquier partido de expresiones regulares es codicioso por defecto. Al modificarlo para que no sea codicioso, la primera coincidencia de patrón no puede incluir los dos puntos, ya que el primer carácter después del paréntesis es dos puntos. La expresión regular después del colon vuelve al valor predeterminado, es decir, codicioso.

+0

¡Gracias por esto! y la explicación de la expresión regular –

3

hace este trabajo (asumiendo que los datos están en un vector de caracteres):

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

(1) Esta es la respuesta que pensé de inmediato. En términos de velocidad, ¿cómo crees que esto se compara con las soluciones de expresiones regulares? – Dason

+0

@Dason También fue mi pensamiento porque realmente no "pienso" en expresiones regulares todavía, pero no tenía muchas esperanzas de velocidad. – joran

1

en este 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 

pueden funcionar para usted

9

Otro enfoque es la búsqueda de la primera ":" y reemplazarlo y nada después con nada:

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

Si no ":" se encontró entonces nada se sustituye y se obtiene el conjunto de la cuerda original Si hay un ":" entonces el primero se combina con todo lo que sigue, esto es reemplazado por nada ("") que lo elimina y deja todo hasta ese primer punto.

3

siento agregar esto como una respuesta.En respuesta a los tiempos tomados:

> 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 

El expresiones regulares son más o menos equivalente al strsplit tarda un poco más

+0

Comentario extendido útil. Me pareció alentador que la expresión regular que parecía lo más simple para mi cerebro, @GregSnow también fuera la más rápida. Las otras dos soluciones de expresiones regulares fueron informativas para su ilustración de las clases de caracteres como una forma de iniciar la "negación" y la explicación del uso de "?" No modificado. para suprimir el comportamiento codicioso. –

Cuestiones relacionadas