2012-01-12 9 views
5

he un vector lleno de cuerdas de la siguiente formato: <year1><year2><id1><id2>R Expresión regular de búsqueda hacia atrás

los primeros valores del vector se parece a esto:

199719982001 
199719982002 
199719982003 
199719982003 

Para la primera entrada tenemos: año 1 = 1997, año2 = 1998, id1 = 2, id2 = 001.

Quiero escribir una expresión regular que extraiga year1, id1 y los dígitos de id2 que no son cero. Así que para la primera entrada de la expresión regular debe de salida: 199721.

he intentado hacer esto con el paquete stringr, y ha creado la siguiente expresión regular:

"^\\d{4}|\\d{1}(?<=\\d{3}$)" 

de sacar año1 e id1, sin embargo cuando se utiliza el mira detrás, me sale un error de "expresión regular inválida". Esto es un poco desconcertante para mí, ¿R no puede manejar lookaheads y mirar detrás?

+3

mira la página de ayuda 'regex'. Lookbehind es compatible con 'perl = TRUE'. Entonces 'regexp ("^\\ d {4} | \\ d {1} (? <= \\ d {3} $) ", s)' no arroja un error, pero no selecciona lo que desea. – mpiktas

+0

¡Gracias por el consejo! Sabía que la expresión regular no captaría todo, solo estaba experimentando un poco, y me pillé cuando recibí un mensaje de "expresión regular no válida". –

+0

Con 'strapply' en gsubfn esta expresión regular funciona y no requiere lookahead o lookbehind:' L <- c ("199719982001", "199719982002", "199719982003", "199719982003"); biblioteca (gsubfn); strapply (L, "^ (....) .... (.) 0 * (. *)", c, simplify = TRUE) ' –

Respuesta

8

Dado que se trata de un formato fijo, ¿por qué no utilizar substr? year1 se extrae utilizando substr(s,1,4), id1 se extrae utilizando substr(s,9,9) y id2 como as.numeric(substr(s,10,13)). En el último caso utilicé as.numeric para deshacerme de los ceros.

+1

Gracias mpiktas, debería haber pensado en eso. Sin embargo, todavía tengo curiosidad por saber por qué no funciona el lookbehind ... –

+0

Ver mi otra respuesta :) – mpiktas

9

Deberá usar gregexpr del paquete base. Esto funciona:

> s <- "199719982001" 
> gregexpr("^\\d{4}|\\d{1}(?<=\\d{3}$)",s,perl=TRUE) 
[[1]] 
[1] 1 12 
attr(,"match.length") 
[1] 4 1 
attr(,"useBytes") 
[1] TRUE 

Tenga en cuenta la configuración perl=TRUE. Para más detalles mira en ?regex.

A juzgar por el resultado, su expresión regular no captura id1 embargo.

1

Puede usar sub.

sub("^(.{4}).{4}(.{1}).*([1-9]{1,3})$","\\1\\2\\3",s) 
+0

¡Gracias por la sugerencia! –