EXPRESIONES REGULARES 1

PILÓN DE LAVA CARACTERÍSTICOS DE LA EROSIÓN DE LAS ESTRUCTURAS VOLCÁNICAS EN TENERIFE, RESTO DE LA DESINTEGRACIÓN Y REBAJE PAULATINOS DE UN ANTIGUO DIQUE, EN LA ZONA DE EL MOLLEDO, SANTIAGO DEL TEIDE, OESTE DE TENERIFE.


   
      Es como un juego. Jugar con las palabras, con los textos, como jugar al Scrabble, construyendo palabras y expresiones (entre otras cosas) pero de una manera un tanto particular. Con lo que acabamos de decir es fácil entender que su ámbito de aplicación son las strings, las cadenas de texto o de caracteres literales, es decir, todo aquéllo que escribamos entre comillas, bien sean simples o dobles.
Y ya veremos que que nos recordarán a algunos de los métodos de las strings que ya conocemos. 


      A ESTAS EXPRESIONES REGULARES SE LAS CONOCE TAMBIÉN COMO REGEX (REGULAR EXPRESSION, EN INGLÉS), Y ASÍ SERÁ COMO NOS REFERIREMOS A ELLAS DE AHORA EN ADELANTE. 👌



Una regex viene a ser, de una manera muy genérica, como un molde para pasteles. Según sea la la forma del molde así será el pastel: cuadrado, redondo, con forma de animalito, más bajo, más alto, más grande, más pequeño, etc... Incluso combinando varias de estas propiedades al mismo tiempo, con lo que conseguiríamos, por ejemplo, mediante un único molde de cartón u hojalata un delicioso pastel de crema y chocolate redondo, de unos cinco centímetros de altura y unos veinte centímetros de diámetro (para no cogernos un empacho).



Visto así, un molde es como un PATRÓN que aplicamos sobre una masa dulce para obtener el pastel que queremos. Aplicado todo esto a las cadenas, éstas, las cadenas, las strings, ya serían nuestra masa dulce ya preparada, con sus ingredientes → cada carácter literal, ya perfectamente ligados como tal masa → el texto completo y convenientemente envuelto entre comillas, sobre el que aplicaremos un molde → nuestro PATRÓN, es decir, nuestra regex, que nos permitirá conseguir ese pastel (o trozos de éste, como ya veremos) tan sabroso y apetecible de acuerdo a nuestros gustos y/o necesidades.
De la misma manera que podemos optar por distinto moldes para "moldear" nuestros pasteles, disponemos de distintas regex que, a modo de patrones, nos permiten igualmente "moldear" nuestros textos.
Vistas más de cerca, constituyen una suerte de metalenguaje, y que nadie se asuste, que no es para tanto: una forma de lenguaje propio y específico, una suerte de lenguaje de descripción de texto usado por todos los lenguajes de computación modernos como C, Perl, Java, Python, etc.
Por este motivo usaremos caracteres literales para llamar a las regex, como letras minúsculas y mayúsculas, barras, asteriscos, etc. para manipular textos. Es más: ya hemos utilizado en nuestros ejemplos en apartados anteriores algunas regex sin "darnos cuenta", como "\n", para obtener saltos de línea. ¡Sorpresa!


Ahora cabría preguntarnos sobre su utilidad, para qué sirven las regex. Pues bien, veamos sus fines, sus objetivos dentro de un programa. Son cuatro:

  1. BÚSQUEDA: Con ciertas similitudes con métodos de las cadenas como str.startwith(), str.endswith() o str.count(), o aún con las mismas slices (rebanadas), apurando un poco. se trata de localizar, de encontrar subcadenas en un texto dado bajo un PATRÓN proporcionado por la propia regex con distintos formatos posibles de manera que se seleccionen unos en detrimento de otros. Por ejemplo, en un listado de archivos de audio que tengamos en nuestro ordenador seleccionar sólo aquéllos que contengan las strings rithmics.mp3, rithmics.wav o rithmics.ogg, en lugar de aquéllos otros que contengan las strings asian_rithmics.mp3 o african_rithmics.wav.
  2. BÚSQUEDA Y SUSTITUCIÓN: Con ciertas similitudes a su vez con el método str.replace() de las strings, el patrón regex localiza primero una concordancia (👀 con la palabrita porque es la clave de esto de las regex y la vamos a emplear por extenso en estos apartados) y la sustituye por otra subcadena distinta.
  3. DIVISIÓN O TROCEADO: Con ciertas similitudes también con métodos como str.split() y str.partition() e, indudablemente, con las slices, se trata de seccionar, trocear, dividir una string allí donde concuerde con el PATRÓN especificado por la regex. Por ejemplo, determinar que cada vez que se encuentre un ";" en la cadena ésta se divida en dos.
  4. VALIDACIÓN: También aquí encontramos ciertas semejanzas con los métodos str.startwith() y str.endswith(), determina si una cadena se ajusta a cierto PATRÓN especificado por la regex. Por ejemplo, si en una lista de ficheros de texto todos ellos tienen la misma extensión .txt a partir del carácter literal ".".
   
      GROSSO MODO (es que yo sé ladrar en latín), NOS PERMITE REPETIR UNA CADENA DADA UN NÚMERO DE n VECES; QUE SE SELECCIONE Y MUESTRE UNA SUBCADENA ENTRE DISTINTAS OPCIONES; ELIMINAR CADENAS SIMPLES EN DISTINTAS PARTES DE OTRAS, MÁS COMPLEJAS; ELEGIR DETERMINADOS CARACTERES LITERALES ENTRE OTROS DADA UNA CADENA CUALQUIERA; LOCALIZAR SUBCADENAS AL PRINCIPIO Y/O AL FINAL DE UNA CADENA; CONTROLAR FORMATOS DE SALIDA DE FORMA SIMPLE Y EFICAZ;  ETC.




La forma sintáctica más básica de una regex puede ser la de un único carácter literal, por ejemplo, e, seguido opcionalmente, entre paréntesis, ( ), por un valor que ejerce de cuantificador: e(5). En sus formas más compleja podemos hablar de una secuencia de caracteres literales cada uno de los cuales, con sus cuantificadores o no, aportando sendos patrones a una misma cadena de texto, con elementos propios de las regex que les permiten perfilar y ser aún más precisas, más escrupulosas, en su trabajo, como las afirmaciones o los marcadores, de los que hablaremos más adelante.
Por ejemplo, podemos decir sin despeinarnos un sólo pelo que el \n, el salto de línea de toda nuestra pythoniana vida, es una regex simple. ¡Sí, como suena!, o aún, la simple barra, \, para escapar caracteres especiales también lo es.
En el caso de que a estas regex simples no se les pase cuantificador alguno, es decir, un número entero que determine el número de concurrencias que deben darse entre el patrón proporcionado y el texto donde se aplica, se tomará SÓLO la primera concordancia. Por ejemplo, si pasamos como patrón "abra" sobre "abracadabra" sólo se aplicará en las primeras cuatro letras de la cadena; si lo hacemos con un cuantificador, por ejemplo, "abra"(3), intentará buscar tres coincidencias lo que, aplicado a nuestro ejemplo, devolverá las primeras cuatro letras y las cuatro últimas: "abraabra". Como en la cadena solo concuerdan con el patrón dos "abra" antes de llegar al final, no buscará una tercera coincidencia pero tampoco lanzará una excepción: el cuantificador buscará, si las hay, tantas coincidencias como le apunte el entero.

FLORACIÓN EN SAN JOSÉ DE LOS LLANOS,
NORTE DE TENERIFE.
Este metalenguaje regex puede utilizar cierto número de caracteres especiales, o metacaracteres, que permiten determinar, ajustar y afinar las características del patrón que queremos aplicar sobre una cadena. Y esto implica el recurso de símbolos, como algún que otro operador aritmético, por ejemplo, todos ellos de fácil acceso en el teclado de nuestro equipo. En síntesis, son caracteres literales normales y corrientes que adquieren, dentro de la aplicación de las regex, un significado  exclusivo o especial para ejecutar ciertas acciones sobre los textos. Para que puedan cumplir con esta función se los tienen que "escapar", recordemos, insertando una contrabarra (backslash o barra invertida), \, si los queremos utilizar como literales.
Veamos cuáles son:





Casi todos los escapes que ya conocemos, como \n o \t, para el salto de línea y la tabulación, respectivamente, son susceptibles de ser empleados en un patrón regex.
Si deseamos encontrar concordancias usando como patrón un conjunto o una serie de caracteres literales, como el caso de "abra" en el ejemplo anterior, lo podemos conseguir recurriendo a lo que se denomina CLASE DE CARÁCTER.
Una CLASE DE CARÁCTER no es otra cosa que uno o más caracteres literales colocados entre corchetes como, por ejemplo, [abdt], [463], [\Sa^3-7], en infinitas combinaciones posibles  que funcionan exactamente igual que una expresión. Y aún más: rizando el rizo, si queremos crear una CLASE DE CARACTERES que contenga corchetes como tales debemos proceder del mismo modo, usando \ como escape: [xyz\[\]] → coincide con x, y, z, [ y ].
Pero, eso sí, si no le pasamos un cuantificador al patrón, sólo aplicará la concordancia sobre la primera concurrencia de  la CLASE DE CARÁCTER ignorando los demás. Veamos un ejemplo:




Siguiendo con esta lógica podemos concordar con un sólo dígito con un regex como [0-9], donde el operador - actúa como un delimitador de rango, es decir, será válido cualquier carácter entre 0 y 9, ambos incluidos. Podemos entender rango como una suerte de CLASE DE CARACTERES concisa, abreviada, bajo la fórmula de escribir tras el corchete de apertura el primer carácter a localizar, incluido; un guión, -, que señala a todo lo que va en orden numérico, de 0 a 9,  y alfabético, de a a z, entre el primer carácter y el último; y el último carácter a localizar, justo antes del corchete de cierre, también incluido.
Es posible, incluso, combinar ambas opciones en una misma regex:

                  • [u-z] [uvwxyz]
                  • [3-7] [34567]
                  • [u-z3-7] [uvwxyz34567]



Puede ocurrir que, por alguna razón nos interese localizar también, mire usted por dónde, el propio "operador" - como un carácter más a localizar en el patrón. Si es así, tenemos tres opciones: o bien lo colocamos al principio, o bien al final (da igual donde lo coloquemos porque tanto los símbolos como los caracteres especiales de nuestro teclado, al contrario que los números y el alfabeto, no siguen ningún orden preestablecido: no se ordenan de 0 a 9 o de a a z, no existe un orden, por ejemplo de ! a & o de % a +), o bien lo escapamos con la contrabarra. De no hacerlo así, el motor regex intenta crear un rango basándose en su condición de metacarácter y,... claro, o nos da error o, simplemente, no cumple con su función. Vamos a verlo: si queremos localizar en una cadena dad los caracteres e, x, 7 y -, podemos proceder de las siguientes tres maneras a elegir: [-ex7], [ex7-] o [ex\-7]. Y si buscamos entre rangos, por ejemplo, [a-g], [-a-g], [a-g-] y [a-g\-], siendo la regex más clara (legible) la última opción, con el escape.
Todo lo anterior, si nos fijamos bien, es asertivo, es decir, que sí, que efectivamente queremos obtener coincidencias con estos caracteres en una cadena dada. Pero podemos volver en negativo el sentido de una CLASE DE CARACTERES  añadiendo al comienzo un acento circunflejo, ^, con lo que estamos diciendo qué caracteres no queremos que aparezcan:
[xyz] → cualquier carácter que sea x, y o z.
[^xyz] → cualquier carácter que no sea x, y o z.
[^s-z] → cualquier carácter que no esté entre s y z, ambos incluidos.
[^0-9] → cualquier carácter que no sea un dígito (de 0 a 9 ocupa todo el rango de números posible).
[^\-] → cualquier carácter que no sea un guión.

VISTA DE LA ZONA NOROESTE DE TENERIFE, HACIA EL ACANTILADO DE LA CULATA, AL FONDO, DESDE EL MONTEVERDE DE PINOLERE, LA OROTAVA, CENTRO NORTE DE TENERIFE.

Para facilitarnos aún más las cosas, las regex más comunes, aquéllas más socorridas, admiten un formato abreviado, más escueto. Salvo el punto, ., todos estos formatos abreviados comienzan con una contrabarra y un carácter literal: d, s y w, en minúsculas y mayúsculas, con un significado diferente en ambos casos.
La d apunta a 'digits' (dígitos), la s apunta a 'spaces' (espacios en blanco) y, por último,  la w apunta a 'word' (cualquier carácter que represente a una letra o a un dígito indistintamente).
Lo apreciaremos mejor en la siguiente tabla:


      CUANTIFICADORES:

      
      Si con las CLASES DE CARACTERES es posible encontrar coincidencias de letras y/o dígitos en una cadena dada, los cuantificadores nos permiten determinar la cantidad de coincidencias (o de no coincidencias, si fuera el caso) a buscar en esa misma cadena.
Estos cuantificadores adoptan una sintaxis característica de forma que se sitúan precediendo a una expresión regex con una estructura como la que e muestra:


Así mínimo es la cantidad mínima de coincidencias con la expresión y máximo la cantidad máxima. Vemos un ejemplo:


Aunque, como acabamos de comprobar en el ejemplo, es posible usar un mismo valor para el mínimo y el máximo, lo que subsidiariamente implica un número fijo de concordancias, por ejemplo, en el primer caso, una única ocurrencia de 'a' (tengamos presente, a pesar de que resulte de perogrullo decirlo, que el segundo parámetro, como su nombre indica, es un máximo, y sólo puede ser igual o mayor que el valor del mínimo, si no queremos que nos dé error, por supuesto, ambos valores enteros y positivos), lo normal es que ambos valores, el mínimo y el máximo, sean distintos, diferentes.
De modo similar a las CLASES DE CARÁCTER que por su uso común, en algunas estructuras completas, gozaban de una sintaxis propia, recordemos, \d, \D, \s, \S, \w, \W y el punto, ., los cuantificadores de uso más frecuentes también cuentan con la suya propia: la codificación {0,1} cuenta con el constructo abreviado: ? . Así, {0,1} = ?
Veamos un nuevo ejemplo:


Existen otras dos abreviaturas más: +, que equivale a {1,n} que coinciden con, al menos, 1 ó más concurrencias del patrón; y *, que equivale a {0,n} que coinciden con 0 ó más concurrencias del patrón. donde n, en ambos casos representa la cantidad máxima de coincidencias que queramos consignar, ya sea 2, 500 ó 10000. Habitualmente, se deja su espacio vacío, como veremos en el listado, para que n valga la cantidad máxima admisible por el cuantificador.

ROQUE DE FUERA, AL CENTRO Y AL FONDO, EN LOS ROQUES DE FASNIA, COSTA SUR DE TENERIFE.


El cuantificador + es, quizás, la mejor opción para concordar dígitos repetidos mediante la regex \d+ (\d, cualquier dígito entre 0 y 9, y +, una o más ocurrencias) y, por ejemplo, eliminarlos de una lista o cualquier otra secuencia mutable, menos problemático que el uso de los cuantificadores * y ? que pueden arrojar resultados inesperados.
Debemos tener muy en cuenta que todos los cuantificadores son voraces por defecto, esto es, que procurará concordar la mayor cantidad posible de caracteres. Por eso, siguiendo el ejemplo anterior, si pasamos 2018\d+ localizará todas las coincidencias con la expresión 2018 habidos y por haber en el código donde lo apliquemos, sin distinguir que formen parte de una función, de un comentario, de la documentación, etc. Vamos, que se lo come todo...
Entonces, ¿cómo controlar esa privacidad? ¿Cómo conseguir anular la voracidad de un cuantificador para conseguir un mínimo de coincidencias y no un porrón... ¡Venga! ¡Hala!...
Pues añadiendo al final, delante del cuantificador el símbolo ?. Recordemos que tal cual viene a ser lo mismo que al cuantificador expresión{0,1}, que instalado junto a un cuantificador consigue ponerle "el bozal al perro" y limita su voracidad.

  • 2018\d+?: Concuerda la expresión 2018 en varios lugares distintos, pero con un máximo de una vez (voracidad limitada).
  • 2018\d+??: Concuerda uno o ningún dígito con la expresión 2018 aunque, como hemos limitado su voracidad incluso con un doble ?, prefiere ninguna concordancia. Casi, es la anulación de la voracidad: es bastante parecido a [^2018].
Pongamos un ejemplo práctico. Imaginemos que tenemos un documento xml donde consignamos un listado de archivos de música almacenados en nuestro disco duro:

                                                                         <música>
                                                                                  <artista>.....................</artista>
                                                                                  <tema>.......................</tema>
                                                                                  <género>....................</género>
                                                                         </música>


Queremos concordar todas las etiquetas <artista>. Podemos optar por esta solución: <artista[^/]+>. Así nos garantizamos que devuelva una etiqueta de apertura del nodo <artista> pero no la de cierre, </artista>. Y si queremos sólo las etiquetas de cierre, sean el nodo que sean, </?.

VISTA DE LA VERTIENTE SUR (O SOTAVENTO) DEL MACIZO DE ANAGA DESDE LA CARRETERA DE LA CUMBRE, NORESTE DE TENERIFE.

      AGRUPACIÓN Y CAPTURA:

   
      La ALTERNACIÓN resulta muy útil como forma de concordar  un patrón determinado entre varias posibilidades. Se emplea el símbolo |, una barra vertical, para separar unas de otras. Por ejemplo, automóvil|autobús|motocicleta|autocaravana. El regex que acabamos de crear concordará con todas aquellas cadenas de texto que contengan "automóvil" o "autobús" o "motocicleta" o "autocaravana". Sin embargo, podemos abreviar la sintaxis del siguiente modo:



Con este constructo utilizamos los paréntesis, ( ), para agrupar elementos comunes, como en este caso, el propio "auto", que es común a tres de nuestros patrones de búsqueda: "automóvil", "autobús" y "autocaravana"; y lo anteponemos a los paréntesis, guardando sólo en su interior aquéllo que no coincide entre sí: los morfemas raíces "móvil", "bus" y "caravana", por supuesto, separados entre ellos por la barra vertical |, que también separa a su vez este conjunto de opciones de "motocicleta".
Así pues, los paréntesis permiten agrupar expresiones que compartan parte de su sintaxis (en el ejemplo, el prefijo "auto-"):



Lo que nos permite trabajar con fórmulas abreviadas, sino que también nos permite CAPTURAR todo texto que concuerde con una expresión: si escribimos el regex anterior de esta forma (automóvil|autobús|autocaravana|motocicleta), no sólo se producirá una concordancia con las cuatro expresiones anteriores sino que, además, generará una captura de la propia expresión.
Como acabamos de decir, toda expresión, incluidas las agrupadas como es el caso de arriba, entre paréntesis, son susceptibles de llevar un bonito cuantificador de temporada. Y de manera similar a lo que ya hemos visto, el cuantificador predeterminado es uno. Si, por ejemplo, nos basamos en los diccionarios de Python clave (key): valor (value), partiendo de la base de que, por ejemplo, la clave es un número entero y el valor una cadena de texto, como puede ser 1:"a", podemos seleccionar todos los ítems del diccionario del modo siguiente:


Cualquiera de las agrupaciones (\w+) o (.+) nos sirve, pudiéndolas usar indistintamente.
Para finalizar, recordemos que | nos permite crear un regex con dos o más opciones: sota|caballo|rey coincidirá con "sota", con "caballo" y con "rey". Y que la función de los paréntesis, ( ), es la de AGRUPAR y CAPTURAR patrones, de manera que un trozo de cadena o más sean capturados si coinciden, por lo que el ámbito natural de las agrupaciones son los textos. También permite acotar el alcance de un cuantificador:
  • xyz+ coincidirá con: xyz, xyzz, xyzzz, xyzzzz, xyzzzzz, xyzzzzzz, etc.
  • (xyz)+ coincidirá con: xyz, xyzxyz, xyzxyzxyz, xyzxyzxyzxyz, xyzxyzxyzxyzxyz, etc.

      AFIRMACIONES Y MARCADORES:

   
     La función de una afirmación es la de limitar el ámbito de las concordancias de un patrón regex determinado, donde, por ejemplo, la afirmación \b establece la frontera entre el carácter que debe ir antes del regex, que puede ser un texto, \w, y el carácter que sigue al patrón, el que viene a continuación, vamos, no debe ser word, \w, y al contrario: que el primero no sea word pero el siguiente sí, lo que nos permite afinar más el criterio de búsquedas de coincidencias:


LAURISILVA Y MONTEVERDE EN LOS ALREDEDORES DE LA CUMBRILLA, NORESTE DEL MACIZO DE ANAGA, NORESTE DE TENERIFE.

TABLA DE AFIRMACIONES




Algunos de estos símbolos pueden ver modificado su significado por los llamados marcadores, una suerte de modificadores que proporciona el módulo re, de regular expresions, del que hablaremos dentro de poco que permiten matizar o, directamente, modificar el comportamiento del patrón regex. Actúan como un segundo parámetro y sus efectos son acumulables añadiendo modificadores ad infinitum, separados por |.

TABLA DE MARCADORES




Como los regex, según nuestras necesidades de programación (que igual los utilizamos o no según requiera nuestro proyecto, o con mayor o menor complejidad), pueden resultar algo confusos de leer podemos, y constituye en sí una buena práctica, acompañarlos de comentarios, bien el de única línea, con #, o si necesitamos de varias líneas, """ ....... """, comillas triples. Veamos un ejemplo con nuestro xml <artista>...</artista>.



Uno de sus mayores utilidades  pasa por capturar nombres y apellidos concretos de una lista dada con nombres y apellidos que se puedan repetir, del mismo modo con una lista de DNIs, de números de la Seguridad Social, rangos profesionales dentro de una institución o de una empresa, etc.
Por ejemplo, tenemos los siguientes nombres en una lista: José María Gómez, José Carlos Gómez y Ana María Gómez, y queremos seleccionar sólo al segundo. Podríamos escribir el siguiente regex:



O, por ejemplo, entre varios DNIs queremos seleccionar exclusivamente el 73496110q, con lo que podríamos proceder del modo siguiente:




Podríamos reforzar nuestro patrón regex incorporando alguna afirmación más:



Y si quisiéramos que no concordase con Gómez, por ejemplo, José Carlos Gámez o José Carlos Gomara, podríamos pasar a negativo la afirmación "mirar hacia adelante" anterior:



Para ir concluyendo con las propiedades genéricas del metalenguaje regex, y antes de pasar a su aplicación desde Python a través del módulo re de la biblioteca estándar, la stdlib, trataremos el tema de lo duplicados. Ya sabemos cómo concordar expresiones duplicadas usando números para indicar el número de veces que puede concordar (repetirse):


Contamos también con la sintaxis (?=nombre) asociada a un regex del tipo (?P<.nombre>) que refiere lo que se conoce como CAPTURAS DENOMINADAS o NOMBRADAS, y que sustituye a los números, \número, como en el ejemplo anterior cuando utilizamos regex complejos y queremos concordar cualquier palabra duplicada:

                                                       (?P<roma>\w+)\s+(?P=roma)
                                                                                                                    
                                                                            nombre                         nombre

Este regex establece coincidencias con duplicados de la captura 'roma'.
Pues bien, podemos establecer concordancias en función se haya determinado o no una coincidencia previa con la expresión para lo que, según fuera el caso, podemos optar por por dos planteamientos sintácticos:


Con esto terminamos nuestra inmersión en el metalenguaje regex y nos adentramos en el módulo re de Python, y que es el específico del lenguaje para hacer uso en nuestros programas de las regex, donde recogeremos la sintaxis que hemos visto hasta ahora y cuyos métodos (funciones) obedecerán a aquellas acciones que hemos conocido como cabeceras de apartados en esta entrega REGEX I: búsquedas, sustituciones, afirmaciones,... Bajo el estándar NFA, apoyándose en la comparación de todos y cada uno de sus elementos de la regex, secuencialmente y de izquierda a derecha, con una entrada en formato string.
El módulo re actúa sobre los patrones regex con las que filtramos las expresiones de dos maneras complementarias: Por un lado, a cada función se le pasará un regex concreto como argumento principal y actúa sobre él compilándolo, esto es, traduciéndolo a un formato propio digerible por el estómago 'delicado' del código máquina para, después, haciendo uso de este patrón resultante de la compilación propiamente dicha; por el otro, actuar sobre la expresión directamente, sin compilar ni ná, a lo heavy.
De entrambas, el primero de los procedimientos, el compilado, resulta bastante útil si vamos a utilizar el regex en varias ocasiones (o todas las que consideremos oportunas, sin límite alguno) en nuestro código. Aún utilizándolo una única vez, constituye en sí una buena práctica efectuar un compilado dado que reduce nuestro código y, a la par, aumenta y mejora su optimización.



Veámoslo de forma codificada en la siguiente comparación:




  CONTINUAMOS EN EXPRESIONES REGULARES 2.




CAUCE MEDIO DEL BARRANCO DEL CERCADO, EN SAN ANDRÉS, ANAGA SUR, TRAS LAS PRIMERAS LLUVIAS DE OTOÑO, NORESTE DE TENERIFE.

No hay comentarios:

Publicar un comentario