Cortar una cadena por un caracter solo cuando no forme parte de una subcadena entrecomillada

Algunos usuarios del paquete pxR han avisado de un error de implementación. Según las especificaciones del formato de datos PC-Axis, las líneas de ese tipo de ficheros acaban en punto y coma (y no necesariamente en un salto de línea).

Así que era natural leer los ficheros íntegramente, concatenar sus líneas físicas y luego partirlas usando strsplit para obtener las líneas lógicas.

Sin embargo, ciertos ficheros contienen descripciones (entrecomilladas) que contienen puntos y comas. Y eso produce caos.

El problema planteado consiste entonces en partir una cadena por un determinado caracter (punto y coma en nuestro caso) solo cuando no forme parte de una subcadena entrecomillada. Lancé la pregunta en r-help-es y obtuve algunas respuestas desiguales. La más próxima a la respuesta que quería era la de Francisco Viciana que funcionaba… excepto cuando en la cadena había caracteres no ASCII (o multibyte) por alguna razón técnica que se me escapa.

Así que me manché las manos y he aquí la solución con la que vine a dar:

library(stringr)
 
a <- '1,2,"algo;todo"; 3,"¿cósa"; 4,2,3,7;'
 
punto.coma <- str_locate_all(a, ";")[[1]][,1]
comillas <- str_locate_all(a, '"')[[1]][,1]
 
cortes <- Filter( function(x) sum(comillas < x) %% 2 == 0, punto.coma )
 
inicios <- c(1, cortes + 1)
finales <- c(cortes - 1, str_length(a))
 
str_sub(a, inicios, finales)

El quid reside en la llamada a Filter, que selecciona solo aquellas posiciones en las que hay puntos y comas que no están precedidas por un número impar de comillas. El paquete stringr resulta instrumental: proporciona recursos para procesar cadenas de texto no disponibles de una manera tan limpia y escueta entre las básicas de R.

2 comentarios sobre “Cortar una cadena por un caracter solo cuando no forme parte de una subcadena entrecomillada

  1. Ender Muab'Dib 4 marzo, 2013 11:44

    Muy buena solución aplicando Filter. Pero ¿y si hay comillas dentro de una de esas descripciones? Creo que se te desbarataría todo. Quizás habría que eliminar todas las coincidencias con comillas escapadas (\») antes de obtener las posiciones de comillas. ¡Pero ojo! También puede darse el caso de que un texto termine en contrabarra: «menganito\\», y esas comillas sí serían válidas.

    Si se quiere incidir en el uso de Filter, se podrían obtener las posiciones de las contrabarras en una variable aparte y quedarse con las comillas que no estén precedidas por una contrabarra, pero sí por dos, aunque igual complica mucho la función de aceptación…

    Un saludo.

  2. datanalytics 5 marzo, 2013 0:27

    @Ender Muab’Dib Tienes razón, potencialmente hay muchas opciones. Y en este caso me he decantado por una que permite pasar de leer bien el 99 % de los ficheros al 99,95 % de ellos.

    Pero seguro que habrá que tapar otro agujero cualquier día.

    (Esta manera mía de hacer me recuerda a la de los programadores que cobran por bug/hora, ¡qué vergüenza!).

Los comentarios están desabilitados.